{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Collaborating Filltering, Matrix Factorization.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "collapsed_sections": [
        "VLyHpP9GcNI8",
        "ZecYlb32aPRG",
        "7Gnr6yC9VqxW",
        "WwawVY_MeCDi",
        "SdbppJj0seHC",
        "PHwhGmC5YtGj",
        "EfLvsj9ax5Bp",
        "9CMimleIm8xp",
        "wqAAa_8JvpVi",
        "kbW3AkTRxKfO",
        "ZdpQw7tNxB23",
        "NlyBl-d00vbS",
        "vbBp9pYqy_C8",
        "WoOWizoNHuWC",
        "gta8xQuwg0_l"
      ],
      "machine_shape": "hm",
      "include_colab_link": true
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.3"
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/dean-sh/Movie-Ratings-with-SVD/blob/master/Collaborating%20Filltering%20%2C%20Matrix%20Factorization.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AI8iUPuAgW34",
        "colab_type": "text"
      },
      "source": [
        "MovieLens Recommendations - Collaborating Filltering, Matrix Factorization\n",
        "=============================================\n",
        "## Dean Shabi, Dedi Kovatch, July 2019\n",
        "## Final Project for TCDS - Technion Data Science Specialization\n",
        "\n",
        "MovieLens data sets were collected by the GroupLens Research Project\n",
        "at the University of Minnesota.\n",
        " \n",
        "This data set consists of:\n",
        "\t* 100,000 ratings (1-5) from 943 users on 1682 movies. \n",
        "\t* Each user has rated at least 20 movies. \n",
        "        * Simple demographic info for the users (age, gender, occupation, zip)\n",
        "\n",
        "The data was collected through the MovieLens web site\n",
        "(movielens.umn.edu) during the seven-month period from September 19th, \n",
        "1997 through April 22nd, 1998. This data has been cleaned up - users\n",
        "who had less than 20 ratings or did not have complete demographic\n",
        "information were removed from this data set. Detailed descriptions of\n",
        "the data file can be found at the end of this file.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VLyHpP9GcNI8",
        "colab_type": "text"
      },
      "source": [
        "## Data Description\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "79B5aQBncSJn",
        "colab_type": "text"
      },
      "source": [
        "\n",
        "Here are brief descriptions of the data.\n",
        "\n",
        "ml-data.tar.gz   -- Compressed tar file.  To rebuild the u data files do this:\n",
        "                gunzip ml-data.tar.gz\n",
        "                tar xvf ml-data.tar\n",
        "                mku.sh\n",
        "\n",
        "u.data     -- The full u data set, 100000 ratings by 943 users on 1682 items.\n",
        "              Each user has rated at least 20 movies.  Users and items are\n",
        "              numbered consecutively from 1.  The data is randomly\n",
        "              ordered. This is a tab separated list of \n",
        "\t         user id | item id | rating | timestamp. \n",
        "              The time stamps are unix seconds since 1/1/1970 UTC   \n",
        "\n",
        "u.info     -- The number of users, items, and ratings in the u data set.\n",
        "\n",
        "u.item     -- Information about the items (movies); this is a tab separated\n",
        "              list of\n",
        "              movie id | movie title | release date | video release date |\n",
        "              IMDb URL | unknown | Action | Adventure | Animation |\n",
        "              Children's | Comedy | Crime | Documentary | Drama | Fantasy |\n",
        "              Film-Noir | Horror | Musical | Mystery | Romance | Sci-Fi |\n",
        "              Thriller | War | Western |\n",
        "              The last 19 fields are the genres, a 1 indicates the movie\n",
        "              is of that genre, a 0 indicates it is not; movies can be in\n",
        "              several genres at once.\n",
        "              The movie ids are the ones used in the u.data data set.\n",
        "\n",
        "u.genre    -- A list of the genres.\n",
        "\n",
        "u.user     -- Demographic information about the users; this is a tab\n",
        "              separated list of\n",
        "              user id | age | gender | occupation | zip code\n",
        "              The user ids are the ones used in the u.data data set.\n",
        "\n",
        "u.occupation -- A list of the occupations.\n",
        "\n",
        "u1.base    -- The data sets u1.base and u1.test through u5.base and u5.test\n",
        "u1.test       are 80%/20% splits of the u data into training and test data.\n",
        "u2.base       Each of u1, ..., u5 have disjoint test sets; this if for\n",
        "u2.test       5 fold cross validation (where you repeat your experiment\n",
        "u3.base       with each training and test set and average the results).\n",
        "u3.test       These data sets can be generated from u.data by mku.sh.\n",
        "u4.base\n",
        "u4.test\n",
        "u5.base\n",
        "u5.test\n",
        "\n",
        "ua.base    -- The data sets ua.base, ua.test, ub.base, and ub.test\n",
        "ua.test       split the u data into a training set and a test set with\n",
        "ub.base       exactly 10 ratings per user in the test set.  The sets\n",
        "ub.test       ua.test and ub.test are disjoint.  These data sets can\n",
        "              be generated from u.data by mku.sh.\n",
        "\n",
        "allbut.pl  -- The script that generates training and test sets where\n",
        "              all but n of a users ratings are in the training data.\n",
        "\n",
        "mku.sh     -- A shell script to generate all the u data sets from u.data."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZecYlb32aPRG",
        "colab_type": "text"
      },
      "source": [
        "## Imports\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "eSXwQhcbxpTA",
        "colab": {}
      },
      "source": [
        "import numpy as np\n",
        "import pandas as pd\n",
        "import collections\n",
        "import seaborn as sns\n",
        "%matplotlib inline\n",
        "# from mpl_toolkits.mplot3d import Axes3D\n",
        "from IPython import display\n",
        "from matplotlib import pyplot as plt\n",
        "import sklearn\n",
        "import sklearn.manifold\n",
        "# import tensorflow as tf\n",
        "# tf.logging.set_verbosity(tf.logging.ERROR)\n",
        "\n",
        "# # Add some convenience functions to Pandas DataFrame.\n",
        "# pd.options.display.max_rows = 10\n",
        "# pd.options.display.float_format = '{:.3f}'.format\n",
        "\n",
        "\n",
        "\n",
        "# # Install Altair and activate its colab renderer.\n",
        "# print(\"Installing Altair...\")\n",
        "# !pip install git+git://github.com/altair-viz/altair.git\n",
        "# import altair as alt\n",
        "# alt.data_transformers.enable('default', max_rows=None)\n",
        "# alt.renderers.enable('colab')\n",
        "# print(\"Done installing Altair.\")\n",
        "\n",
        "# # Install spreadsheets and import authentication module.\n",
        "# USER_RATINGS = False\n",
        "# !pip install --upgrade -q gspread\n",
        "# from google.colab import auth\n",
        "# import gspread\n",
        "# from oauth2client.client import GoogleCredentials"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7Gnr6yC9VqxW",
        "colab_type": "text"
      },
      "source": [
        "## **Importing dataset, preprocessing**\n",
        "\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gq9LYL4ef_Ms",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# download the MovieLens Data, and create DataFrames containing movies, users, and ratings.\n",
        "\n",
        "print(\"Downloading movielens data...\")\n",
        "import zipfile\n",
        "import urllib.request\n",
        "\n",
        "urllib.request.urlretrieve(\"http://files.grouplens.org/datasets/movielens/ml-100k.zip\", \"movielens.zip\")\n",
        "zip_ref = zipfile.ZipFile('movielens.zip', \"r\")\n",
        "zip_ref.extractall()\n",
        "print(\"Done. Dataset contains:\")\n",
        "print(zip_ref.read('ml-100k/u.info'))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Ny6Op3qUe3bc",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Load each data set (users, movies, and ratings).\n",
        "users_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code']\n",
        "users = pd.read_csv(\n",
        "    'ml-100k/u.user', sep='|', names=users_cols, encoding='latin-1')\n",
        "\n",
        "ratings_cols = ['user_id', 'movie_id', 'rating', 'unix_timestamp']\n",
        "ratings = pd.read_csv(\n",
        "    'ml-100k/u.data', sep='\\t', names=ratings_cols, encoding='latin-1')\n",
        "\n",
        "# The movies file contains a binary feature for each genre.\n",
        "genre_cols = [\n",
        "    \"genre_unknown\", \"Action\", \"Adventure\", \"Animation\", \"Children\", \"Comedy\",\n",
        "    \"Crime\", \"Documentary\", \"Drama\", \"Fantasy\", \"Film-Noir\", \"Horror\",\n",
        "    \"Musical\", \"Mystery\", \"Romance\", \"Sci-Fi\", \"Thriller\", \"War\", \"Western\"\n",
        "]\n",
        "movies_cols = [\n",
        "    'movie_id', 'title', 'release_date', \"video_release_date\", \"imdb_url\"] + genre_cols\n",
        "\n",
        "movies = pd.read_csv(\n",
        "    'ml-100k/u.item', sep='|', names=movies_cols, encoding='latin-1')\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dXNpqJsDgeqj",
        "colab_type": "text"
      },
      "source": [
        "Some Preproccessing"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xjlkpHekgXyq",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Since the ids start at 1, we shift them to start at 0.\n",
        "users[\"user_id\"] = users[\"user_id\"].apply(lambda x: str(x-1))\n",
        "movies[\"movie_id\"] = movies[\"movie_id\"].apply(lambda x: str(x-1))\n",
        "movies[\"year\"] = movies['release_date'].apply(lambda x: str(x).split('-')[-1])\n",
        "ratings[\"movie_id\"] = ratings[\"movie_id\"].apply(lambda x: str(x-1))\n",
        "ratings[\"user_id\"] = ratings[\"user_id\"].apply(lambda x: str(x-1))\n",
        "ratings[\"rating\"] = ratings[\"rating\"].apply(lambda x: float(x))\n",
        "\n",
        "# Compute the number of movies to which a genre is assigned.\n",
        "genre_occurences = movies[genre_cols].sum().to_dict()\n",
        "\n",
        "# Since some movies can belong to more than one genre, we create different\n",
        "# 'genre' columns as follows:\n",
        "# - all_genres: all the active genres of the movie.\n",
        "# - genre: randomly sampled from the active genres.\n",
        "def mark_genres(movies, genres):\n",
        "    def get_random_genre(gs):\n",
        "        active = [genre for genre, g in zip(genres, gs) if g==1]\n",
        "        if len(active) == 0:\n",
        "            return 'Other'\n",
        "        return np.random.choice(active)\n",
        "    def get_all_genres(gs):\n",
        "        active = [genre for genre, g in zip(genres, gs) if g==1]\n",
        "        if len(active) == 0:\n",
        "            return 'Other'\n",
        "        return '-'.join(active)\n",
        "    movies['genre'] = [\n",
        "        get_random_genre(gs) for gs in zip(*[movies[genre] for genre in genres])]\n",
        "    movies['all_genres'] = [\n",
        "        get_all_genres(gs) for gs in zip(*[movies[genre] for genre in genres])]\n",
        "\n",
        "mark_genres(movies, genre_cols)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "apgLczpJgWcf",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Create one merged DataFrame containing all the movielens data.\n",
        "movielens = ratings.merge(movies, on='movie_id').merge(users, on='user_id')\n",
        "\n",
        "# Utility to split the data into training and test sets.\n",
        "def split_dataframe(df, holdout_fraction=0.1):\n",
        "    \"\"\"Splits a DataFrame into training and test sets.\n",
        "    Args:\n",
        "    df: a dataframe.\n",
        "    holdout_fraction: fraction of dataframe rows to use in the test set.\n",
        "    Returns:\n",
        "    train: dataframe for training\n",
        "    test: dataframe for testing\n",
        "    \"\"\"\n",
        "    test = df.sample(frac=holdout_fraction, replace=False)\n",
        "    train = df[~df.index.isin(test.index)]\n",
        "    return train, test"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XJMhuEXXgXdB",
        "colab_type": "code",
        "outputId": "4e49f141-5aa3-4bf6-84f2-68c491c77716",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "movies.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>movie_id</th>\n",
              "      <th>title</th>\n",
              "      <th>release_date</th>\n",
              "      <th>video_release_date</th>\n",
              "      <th>imdb_url</th>\n",
              "      <th>genre_unknown</th>\n",
              "      <th>Action</th>\n",
              "      <th>Adventure</th>\n",
              "      <th>Animation</th>\n",
              "      <th>Children</th>\n",
              "      <th>Comedy</th>\n",
              "      <th>Crime</th>\n",
              "      <th>Documentary</th>\n",
              "      <th>Drama</th>\n",
              "      <th>Fantasy</th>\n",
              "      <th>Film-Noir</th>\n",
              "      <th>Horror</th>\n",
              "      <th>Musical</th>\n",
              "      <th>Mystery</th>\n",
              "      <th>Romance</th>\n",
              "      <th>Sci-Fi</th>\n",
              "      <th>Thriller</th>\n",
              "      <th>War</th>\n",
              "      <th>Western</th>\n",
              "      <th>year</th>\n",
              "      <th>genre</th>\n",
              "      <th>all_genres</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Toy%20Story%2...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1995</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Animation-Children-Comedy</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>1</td>\n",
              "      <td>GoldenEye (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?GoldenEye%20(...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1995</td>\n",
              "      <td>Adventure</td>\n",
              "      <td>Action-Adventure-Thriller</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>2</td>\n",
              "      <td>Four Rooms (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Four%20Rooms%...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1995</td>\n",
              "      <td>Thriller</td>\n",
              "      <td>Thriller</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>3</td>\n",
              "      <td>Get Shorty (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Get%20Shorty%...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1995</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Action-Comedy-Drama</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>4</td>\n",
              "      <td>Copycat (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Copycat%20(1995)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1995</td>\n",
              "      <td>Crime</td>\n",
              "      <td>Crime-Drama-Thriller</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "  movie_id              title  ...      genre                 all_genres\n",
              "0        0   Toy Story (1995)  ...     Comedy  Animation-Children-Comedy\n",
              "1        1   GoldenEye (1995)  ...  Adventure  Action-Adventure-Thriller\n",
              "2        2  Four Rooms (1995)  ...   Thriller                   Thriller\n",
              "3        3  Get Shorty (1995)  ...     Comedy        Action-Comedy-Drama\n",
              "4        4     Copycat (1995)  ...      Crime       Crime-Drama-Thriller\n",
              "\n",
              "[5 rows x 27 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 6
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "MgCRtomqgXHp",
        "colab_type": "code",
        "outputId": "f890e6f0-1681-42fb-cd98-4417a0abb50a",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "users.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>age</th>\n",
              "      <th>sex</th>\n",
              "      <th>occupation</th>\n",
              "      <th>zip_code</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>0</td>\n",
              "      <td>24</td>\n",
              "      <td>M</td>\n",
              "      <td>technician</td>\n",
              "      <td>85711</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>1</td>\n",
              "      <td>53</td>\n",
              "      <td>F</td>\n",
              "      <td>other</td>\n",
              "      <td>94043</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>2</td>\n",
              "      <td>23</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>32067</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>3</td>\n",
              "      <td>24</td>\n",
              "      <td>M</td>\n",
              "      <td>technician</td>\n",
              "      <td>43537</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>4</td>\n",
              "      <td>33</td>\n",
              "      <td>F</td>\n",
              "      <td>other</td>\n",
              "      <td>15213</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "  user_id  age sex  occupation zip_code\n",
              "0       0   24   M  technician    85711\n",
              "1       1   53   F       other    94043\n",
              "2       2   23   M      writer    32067\n",
              "3       3   24   M  technician    43537\n",
              "4       4   33   F       other    15213"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 7
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "UHVdwsCBgWyl",
        "colab_type": "code",
        "outputId": "eb7bac9f-29b5-467c-ba41-c41603ccd7a6",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "ratings.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "      <th>unix_timestamp</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>195</td>\n",
              "      <td>241</td>\n",
              "      <td>3.0</td>\n",
              "      <td>881250949</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>185</td>\n",
              "      <td>301</td>\n",
              "      <td>3.0</td>\n",
              "      <td>891717742</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>21</td>\n",
              "      <td>376</td>\n",
              "      <td>1.0</td>\n",
              "      <td>878887116</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>243</td>\n",
              "      <td>50</td>\n",
              "      <td>2.0</td>\n",
              "      <td>880606923</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>165</td>\n",
              "      <td>345</td>\n",
              "      <td>1.0</td>\n",
              "      <td>886397596</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "  user_id movie_id  rating  unix_timestamp\n",
              "0     195      241     3.0       881250949\n",
              "1     185      301     3.0       891717742\n",
              "2      21      376     1.0       878887116\n",
              "3     243       50     2.0       880606923\n",
              "4     165      345     1.0       886397596"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 8
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "SlgCWxb9h3Er",
        "colab_type": "code",
        "outputId": "9d57673f-c3e4-4bce-d051-da98d1149c46",
        "colab": {
          "base_uri": "https://localhost:8080/"
        }
      },
      "source": [
        "movielens.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "      <th>unix_timestamp</th>\n",
              "      <th>title</th>\n",
              "      <th>release_date</th>\n",
              "      <th>video_release_date</th>\n",
              "      <th>imdb_url</th>\n",
              "      <th>genre_unknown</th>\n",
              "      <th>Action</th>\n",
              "      <th>Adventure</th>\n",
              "      <th>Animation</th>\n",
              "      <th>Children</th>\n",
              "      <th>Comedy</th>\n",
              "      <th>Crime</th>\n",
              "      <th>Documentary</th>\n",
              "      <th>Drama</th>\n",
              "      <th>Fantasy</th>\n",
              "      <th>Film-Noir</th>\n",
              "      <th>Horror</th>\n",
              "      <th>Musical</th>\n",
              "      <th>Mystery</th>\n",
              "      <th>Romance</th>\n",
              "      <th>Sci-Fi</th>\n",
              "      <th>Thriller</th>\n",
              "      <th>War</th>\n",
              "      <th>Western</th>\n",
              "      <th>year</th>\n",
              "      <th>genre</th>\n",
              "      <th>all_genres</th>\n",
              "      <th>age</th>\n",
              "      <th>sex</th>\n",
              "      <th>occupation</th>\n",
              "      <th>zip_code</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>195</td>\n",
              "      <td>241</td>\n",
              "      <td>3.0</td>\n",
              "      <td>881250949</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "      <td>24-Jan-1997</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Kolya%20(1996)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1997</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>195</td>\n",
              "      <td>256</td>\n",
              "      <td>2.0</td>\n",
              "      <td>881251577</td>\n",
              "      <td>Men in Black (1997)</td>\n",
              "      <td>04-Jul-1997</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Men+in+Black+...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1997</td>\n",
              "      <td>Sci-Fi</td>\n",
              "      <td>Action-Adventure-Comedy-Sci-Fi</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>195</td>\n",
              "      <td>110</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251793</td>\n",
              "      <td>Truth About Cats &amp; Dogs, The (1996)</td>\n",
              "      <td>26-Apr-1996</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Truth%20About...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1996</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy-Romance</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>195</td>\n",
              "      <td>24</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251955</td>\n",
              "      <td>Birdcage, The (1996)</td>\n",
              "      <td>08-Mar-1996</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Birdcage,%20T...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1996</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>195</td>\n",
              "      <td>381</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251843</td>\n",
              "      <td>Adventures of Priscilla, Queen of the Desert, ...</td>\n",
              "      <td>01-Jan-1994</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Adventures%20...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1994</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy-Drama</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "  user_id movie_id  rating  unix_timestamp  ... age sex  occupation zip_code\n",
              "0     195      241     3.0       881250949  ...  49   M      writer    55105\n",
              "1     195      256     2.0       881251577  ...  49   M      writer    55105\n",
              "2     195      110     4.0       881251793  ...  49   M      writer    55105\n",
              "3     195       24     4.0       881251955  ...  49   M      writer    55105\n",
              "4     195      381     4.0       881251843  ...  49   M      writer    55105\n",
              "\n",
              "[5 rows x 34 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 9
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WwawVY_MeCDi",
        "colab_type": "text"
      },
      "source": [
        "# Collaborating Filltering with Surprise library"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "7VAYAq5Q-zXY",
        "colab_type": "code",
        "outputId": "9ba1bb82-d087-466c-c62c-02b33c6ce612",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 235
        }
      },
      "source": [
        "!pip install scikit-surprise\n",
        "\n",
        "from surprise import Reader\n",
        "from surprise import Dataset\n",
        "from surprise.model_selection import cross_validate\n",
        "from surprise import NormalPredictor\n",
        "from surprise import KNNBasic\n",
        "from surprise import KNNWithMeans\n",
        "from surprise import KNNWithZScore\n",
        "from surprise import KNNBaseline\n",
        "from surprise import SVD\n",
        "from surprise import BaselineOnly\n",
        "from surprise import SVDpp\n",
        "from surprise import NMF\n",
        "from surprise import SlopeOne\n",
        "from surprise import CoClustering\n",
        "from surprise.accuracy import rmse\n",
        "from surprise import accuracy\n",
        "from surprise.model_selection import train_test_split"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Collecting scikit-surprise\n",
            "\u001b[?25l  Downloading https://files.pythonhosted.org/packages/4d/fc/cd4210b247d1dca421c25994740cbbf03c5e980e31881f10eaddf45fdab0/scikit-surprise-1.0.6.tar.gz (3.3MB)\n",
            "\u001b[K     |████████████████████████████████| 3.3MB 2.9MB/s \n",
            "\u001b[?25hRequirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (0.13.2)\n",
            "Requirement already satisfied: numpy>=1.11.2 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.16.4)\n",
            "Requirement already satisfied: scipy>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.3.0)\n",
            "Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from scikit-surprise) (1.12.0)\n",
            "Building wheels for collected packages: scikit-surprise\n",
            "  Building wheel for scikit-surprise (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Stored in directory: /root/.cache/pip/wheels/ec/c0/55/3a28eab06b53c220015063ebbdb81213cd3dcbb72c088251ec\n",
            "Successfully built scikit-surprise\n",
            "Installing collected packages: scikit-surprise\n",
            "Successfully installed scikit-surprise-1.0.6\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "F9T0pOIgYX3W",
        "colab_type": "code",
        "outputId": "5cf1167c-9f34-4467-8cfc-1312bb4bbec5",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "min_item_clicks = 50\n",
        "filter_items = movielens['movie_id'].value_counts() > min_item_clicks\n",
        "filter_items = filter_items[filter_items].index.tolist()\n",
        "\n",
        "min_user_clicks = 50\n",
        "filter_users = movielens['user_id'].value_counts() > min_user_clicks\n",
        "filter_users = filter_users[filter_users].index.tolist()\n",
        "\n",
        "df_filtered = movielens[(movielens['movie_id'].isin(filter_items)) & (movielens['user_id'].isin(filter_users))]\n",
        "print('The original data frame shape:\\t{}'.format(movielens.shape))\n",
        "print('The new data frame shape:\\t{}'.format(df_filtered.shape))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "The original data frame shape:\t(100000, 34)\n",
            "The new data frame shape:\t(72829, 34)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FnmEwo2fZUqQ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "reader = Reader(rating_scale=(1, 5))\n",
        "data = Dataset.load_from_df(df_filtered[['user_id', 'movie_id', 'rating']], reader)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "H-jAEnB4Z0y5",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "benchmark = []\n",
        "\n",
        "# Iterate over all algorithms\n",
        "for algo in [SVD(), SVDpp(),SlopeOne(), NMF(), NormalPredictor(), KNNBaseline(), KNNBasic(), KNNWithMeans(), KNNWithZScore(), BaselineOnly(), CoClustering()]:\n",
        "\n",
        "    # Perform cross validation\n",
        "    print('statring cv for {}'.format(algo))\n",
        "    results = cross_validate(algo, data, measures=['RMSE'], cv=5, verbose=False)\n",
        "    \n",
        "    # Get results & appensurprise_results = pd.DataFrame(benchmark).set_index('Algorithm').sort_values('test_rmse')d algorithm name\n",
        "    tmp = pd.DataFrame.from_dict(results).mean(axis=0)\n",
        "    tmp = tmp.append(pd.Series([str(algo).split(' ')[0].split('.')[-1]], index=['Algorithm']))\n",
        "    benchmark.append(tmp)\n",
        "    \n",
        "    "
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "1lmOngCSAr_w",
        "colab_type": "code",
        "outputId": "31049eee-f79d-4658-9c9f-9e06cb0a5ab7",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 402
        }
      },
      "source": [
        "surprise_results = pd.DataFrame(benchmark).set_index('Algorithm').sort_values('test_rmse')\n",
        "surprise_results"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>test_rmse</th>\n",
              "      <th>fit_time</th>\n",
              "      <th>test_time</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>Algorithm</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>SVDpp</th>\n",
              "      <td>0.911311</td>\n",
              "      <td>161.063439</td>\n",
              "      <td>2.572903</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>KNNBaseline</th>\n",
              "      <td>0.920567</td>\n",
              "      <td>0.449645</td>\n",
              "      <td>3.724718</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>SVD</th>\n",
              "      <td>0.926022</td>\n",
              "      <td>4.540039</td>\n",
              "      <td>0.141301</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>SlopeOne</th>\n",
              "      <td>0.934167</td>\n",
              "      <td>0.501804</td>\n",
              "      <td>2.111923</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.935144</td>\n",
              "      <td>0.117489</td>\n",
              "      <td>0.133268</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>KNNWithMeans</th>\n",
              "      <td>0.937647</td>\n",
              "      <td>0.363125</td>\n",
              "      <td>3.235781</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>KNNWithZScore</th>\n",
              "      <td>0.938816</td>\n",
              "      <td>0.412725</td>\n",
              "      <td>3.479334</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>CoClustering</th>\n",
              "      <td>0.945486</td>\n",
              "      <td>1.077938</td>\n",
              "      <td>0.169708</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>NMF</th>\n",
              "      <td>0.951034</td>\n",
              "      <td>4.721857</td>\n",
              "      <td>0.149676</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>KNNBasic</th>\n",
              "      <td>0.959808</td>\n",
              "      <td>0.337485</td>\n",
              "      <td>3.047236</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>NormalPredictor</th>\n",
              "      <td>1.493608</td>\n",
              "      <td>0.110504</td>\n",
              "      <td>0.152135</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                 test_rmse    fit_time  test_time\n",
              "Algorithm                                        \n",
              "SVDpp             0.911311  161.063439   2.572903\n",
              "KNNBaseline       0.920567    0.449645   3.724718\n",
              "SVD               0.926022    4.540039   0.141301\n",
              "SlopeOne          0.934167    0.501804   2.111923\n",
              "BaselineOnly      0.935144    0.117489   0.133268\n",
              "KNNWithMeans      0.937647    0.363125   3.235781\n",
              "KNNWithZScore     0.938816    0.412725   3.479334\n",
              "CoClustering      0.945486    1.077938   0.169708\n",
              "NMF               0.951034    4.721857   0.149676\n",
              "KNNBasic          0.959808    0.337485   3.047236\n",
              "NormalPredictor   1.493608    0.110504   0.152135"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 10
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "EedDGvFcg60_",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#HyperParameterTunning for BaseLineOnly\n",
        "\n",
        "benchmark = []\n",
        "\n",
        "methods = 'als'\n",
        "n_epochs = [10,15,20,40]\n",
        "reg_us = [2, 5 ,10]\n",
        "reg_is = [2, 5, 10]\n",
        "\n",
        "for n_epoch in n_epochs:\n",
        "  for reg_u in reg_us:\n",
        "    for reg_i in reg_is:\n",
        "      bsl_options = {'method': 'als',\n",
        "                     'n_epochs': n_epoch,\n",
        "                     'reg_u': reg_u,\n",
        "                     'reg_i': reg_i}\n",
        "\n",
        "      algo = BaselineOnly(bsl_options=bsl_options)\n",
        "      results = cross_validate(algo, data, measures=['RMSE'], cv=5, verbose=False)\n",
        "\n",
        "      tmp = pd.DataFrame.from_dict(results).mean(axis=0)\n",
        "      tmp = tmp.append(pd.Series([str(algo).split(' ')[0].split('.')[-1]], index=['Algorithm']))\n",
        "      tmp['n_epochs'] = n_epoch\n",
        "      tmp['reg_u'] = reg_u\n",
        "      tmp['reg_i'] = reg_i\n",
        "      benchmark.append(tmp)\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "vN3k7357uW9v",
        "colab_type": "code",
        "outputId": "da10cebc-4e61-4f18-d5d2-7f6496bccb1e",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "surprise_results = pd.DataFrame(benchmark).set_index('Algorithm').sort_values('test_rmse')\n",
        "surprise_results"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>test_rmse</th>\n",
              "      <th>fit_time</th>\n",
              "      <th>test_time</th>\n",
              "      <th>n_epochs</th>\n",
              "      <th>reg_u</th>\n",
              "      <th>reg_i</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>Algorithm</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.918615</td>\n",
              "      <td>0.265777</td>\n",
              "      <td>0.110717</td>\n",
              "      <td>40</td>\n",
              "      <td>2</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.918651</td>\n",
              "      <td>0.091991</td>\n",
              "      <td>0.126337</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.918732</td>\n",
              "      <td>0.264995</td>\n",
              "      <td>0.131282</td>\n",
              "      <td>40</td>\n",
              "      <td>2</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.918965</td>\n",
              "      <td>0.145354</td>\n",
              "      <td>0.127485</td>\n",
              "      <td>20</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919010</td>\n",
              "      <td>0.146003</td>\n",
              "      <td>0.110739</td>\n",
              "      <td>20</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919020</td>\n",
              "      <td>0.272649</td>\n",
              "      <td>0.113949</td>\n",
              "      <td>40</td>\n",
              "      <td>2</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919061</td>\n",
              "      <td>0.086128</td>\n",
              "      <td>0.119886</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919105</td>\n",
              "      <td>0.088744</td>\n",
              "      <td>0.133683</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919206</td>\n",
              "      <td>0.090425</td>\n",
              "      <td>0.129215</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919207</td>\n",
              "      <td>0.085344</td>\n",
              "      <td>0.107060</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919212</td>\n",
              "      <td>0.120712</td>\n",
              "      <td>0.109797</td>\n",
              "      <td>15</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919315</td>\n",
              "      <td>0.267652</td>\n",
              "      <td>0.107653</td>\n",
              "      <td>40</td>\n",
              "      <td>5</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919349</td>\n",
              "      <td>0.148661</td>\n",
              "      <td>0.129287</td>\n",
              "      <td>20</td>\n",
              "      <td>2</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919390</td>\n",
              "      <td>0.272487</td>\n",
              "      <td>0.130644</td>\n",
              "      <td>40</td>\n",
              "      <td>5</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919391</td>\n",
              "      <td>0.268033</td>\n",
              "      <td>0.130101</td>\n",
              "      <td>40</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919400</td>\n",
              "      <td>0.089742</td>\n",
              "      <td>0.109103</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919401</td>\n",
              "      <td>0.150128</td>\n",
              "      <td>0.114241</td>\n",
              "      <td>20</td>\n",
              "      <td>5</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919491</td>\n",
              "      <td>0.117976</td>\n",
              "      <td>0.106645</td>\n",
              "      <td>15</td>\n",
              "      <td>2</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919508</td>\n",
              "      <td>0.118761</td>\n",
              "      <td>0.126062</td>\n",
              "      <td>15</td>\n",
              "      <td>2</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919529</td>\n",
              "      <td>0.120726</td>\n",
              "      <td>0.109301</td>\n",
              "      <td>15</td>\n",
              "      <td>2</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919531</td>\n",
              "      <td>0.145384</td>\n",
              "      <td>0.111837</td>\n",
              "      <td>20</td>\n",
              "      <td>2</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919538</td>\n",
              "      <td>0.264837</td>\n",
              "      <td>0.111942</td>\n",
              "      <td>40</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919538</td>\n",
              "      <td>0.147322</td>\n",
              "      <td>0.130168</td>\n",
              "      <td>20</td>\n",
              "      <td>5</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919560</td>\n",
              "      <td>0.115690</td>\n",
              "      <td>0.127641</td>\n",
              "      <td>15</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919728</td>\n",
              "      <td>0.147620</td>\n",
              "      <td>0.115816</td>\n",
              "      <td>20</td>\n",
              "      <td>2</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919841</td>\n",
              "      <td>0.116800</td>\n",
              "      <td>0.126289</td>\n",
              "      <td>15</td>\n",
              "      <td>5</td>\n",
              "      <td>2</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919888</td>\n",
              "      <td>0.146935</td>\n",
              "      <td>0.114078</td>\n",
              "      <td>20</td>\n",
              "      <td>5</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919891</td>\n",
              "      <td>0.118376</td>\n",
              "      <td>0.109348</td>\n",
              "      <td>15</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.919926</td>\n",
              "      <td>0.118797</td>\n",
              "      <td>0.109218</td>\n",
              "      <td>15</td>\n",
              "      <td>5</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920047</td>\n",
              "      <td>0.119604</td>\n",
              "      <td>0.112020</td>\n",
              "      <td>15</td>\n",
              "      <td>5</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920114</td>\n",
              "      <td>0.089270</td>\n",
              "      <td>0.109798</td>\n",
              "      <td>10</td>\n",
              "      <td>2</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920169</td>\n",
              "      <td>0.089661</td>\n",
              "      <td>0.108169</td>\n",
              "      <td>10</td>\n",
              "      <td>5</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920275</td>\n",
              "      <td>0.267778</td>\n",
              "      <td>0.111919</td>\n",
              "      <td>40</td>\n",
              "      <td>5</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920342</td>\n",
              "      <td>0.148758</td>\n",
              "      <td>0.117763</td>\n",
              "      <td>20</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920342</td>\n",
              "      <td>0.089992</td>\n",
              "      <td>0.108447</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>BaselineOnly</th>\n",
              "      <td>0.920373</td>\n",
              "      <td>0.271069</td>\n",
              "      <td>0.109731</td>\n",
              "      <td>40</td>\n",
              "      <td>10</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "              test_rmse  fit_time  test_time  n_epochs  reg_u  reg_i\n",
              "Algorithm                                                           \n",
              "BaselineOnly   0.918615  0.265777   0.110717        40      2      2\n",
              "BaselineOnly   0.918651  0.091991   0.126337        10     10      2\n",
              "BaselineOnly   0.918732  0.264995   0.131282        40      2      5\n",
              "BaselineOnly   0.918965  0.145354   0.127485        20     10      2\n",
              "BaselineOnly   0.919010  0.146003   0.110739        20     10      5\n",
              "BaselineOnly   0.919020  0.272649   0.113949        40      2     10\n",
              "BaselineOnly   0.919061  0.086128   0.119886        10      2      5\n",
              "BaselineOnly   0.919105  0.088744   0.133683        10      5      2\n",
              "BaselineOnly   0.919206  0.090425   0.129215        10      5      5\n",
              "BaselineOnly   0.919207  0.085344   0.107060        10      2      2\n",
              "BaselineOnly   0.919212  0.120712   0.109797        15     10      2\n",
              "BaselineOnly   0.919315  0.267652   0.107653        40      5      5\n",
              "BaselineOnly   0.919349  0.148661   0.129287        20      2      2\n",
              "BaselineOnly   0.919390  0.272487   0.130644        40      5      2\n",
              "BaselineOnly   0.919391  0.268033   0.130101        40     10      5\n",
              "BaselineOnly   0.919400  0.089742   0.109103        10     10      5\n",
              "BaselineOnly   0.919401  0.150128   0.114241        20      5      2\n",
              "BaselineOnly   0.919491  0.117976   0.106645        15      2     10\n",
              "BaselineOnly   0.919508  0.118761   0.126062        15      2      5\n",
              "BaselineOnly   0.919529  0.120726   0.109301        15      2      2\n",
              "BaselineOnly   0.919531  0.145384   0.111837        20      2      5\n",
              "BaselineOnly   0.919538  0.264837   0.111942        40     10      2\n",
              "BaselineOnly   0.919538  0.147322   0.130168        20      5      5\n",
              "BaselineOnly   0.919560  0.115690   0.127641        15     10      5\n",
              "BaselineOnly   0.919728  0.147620   0.115816        20      2     10\n",
              "BaselineOnly   0.919841  0.116800   0.126289        15      5      2\n",
              "BaselineOnly   0.919888  0.146935   0.114078        20      5     10\n",
              "BaselineOnly   0.919891  0.118376   0.109348        15     10     10\n",
              "BaselineOnly   0.919926  0.118797   0.109218        15      5     10\n",
              "BaselineOnly   0.920047  0.119604   0.112020        15      5      5\n",
              "BaselineOnly   0.920114  0.089270   0.109798        10      2     10\n",
              "BaselineOnly   0.920169  0.089661   0.108169        10      5     10\n",
              "BaselineOnly   0.920275  0.267778   0.111919        40      5     10\n",
              "BaselineOnly   0.920342  0.148758   0.117763        20     10     10\n",
              "BaselineOnly   0.920342  0.089992   0.108447        10     10     10\n",
              "BaselineOnly   0.920373  0.271069   0.109731        40     10     10"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 11
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "wo2n2I4kMAoZ",
        "colab_type": "code",
        "outputId": "203a7cb6-13ce-4de5-eaef-98f981c403b6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 67
        }
      },
      "source": [
        "trainset, testset = train_test_split(data, test_size=0.25)\n",
        "bsl_options = {'method': 'als',\n",
        "               'n_epochs': 40,\n",
        "               'reg_u': 2,\n",
        "               'reg_i': 2}\n",
        "\n",
        "algo = BaselineOnly(bsl_options=bsl_options)\n",
        "predictions = algo.fit(trainset).test(testset)\n",
        "accuracy.rmse(predictions)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Estimating biases using als...\n",
            "RMSE: 0.9256\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "0.9255923566007465"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 12
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xhtVSuHUPKkt",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def get_Iu(uid):\n",
        "    \"\"\" return the number of items rated by given user\n",
        "    args: \n",
        "      uid: the id of the user\n",
        "    returns: \n",
        "      the number of items rated by the user\n",
        "    \"\"\"\n",
        "    try:\n",
        "        return len(trainset.ur[trainset.to_inner_uid(uid)])\n",
        "    except ValueError: # user was not part of the trainset\n",
        "        return 0\n",
        "    \n",
        "def get_Ui(iid):\n",
        "    \"\"\" return number of users that have rated given item\n",
        "    args:\n",
        "      iid: the raw id of the item\n",
        "    returns:\n",
        "      the number of users that have rated the item.\n",
        "    \"\"\"\n",
        "    try: \n",
        "        return len(trainset.ir[trainset.to_inner_iid(iid)])\n",
        "    except ValueError:\n",
        "        return 0\n",
        "    \n",
        "df = pd.DataFrame(predictions, columns=['uid', 'iid', 'rui', 'est', 'details'])\n",
        "df['Iu'] = df.uid.apply(get_Iu)\n",
        "df['Ui'] = df.iid.apply(get_Ui)\n",
        "df['err'] = abs(df.est - df.rui)\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "lO7UC_eogv6y",
        "colab_type": "code",
        "outputId": "385672c7-a91c-48ce-80e7-242e8a9c0f56",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 101
        }
      },
      "source": [
        "df_ToMerge =  movies\n",
        "\n",
        "\n",
        "df_ToMerge =  movielens[['user_id', 'movie_id', 'rating', 'title',\n",
        "       'genre_unknown','Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Crime',\n",
        "       'Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'Musical',\n",
        "       'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western', 'year',\n",
        "       'genre', 'all_genres', 'age', 'sex', 'occupation']]\n",
        "\n",
        "df_ToMerge.rename(columns={'movie_id': 'iid'}, inplace=True)\n",
        "df = df.merge(df_ToMerge, on='iid', how='left' )"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.6/dist-packages/pandas/core/frame.py:4025: SettingWithCopyWarning: \n",
            "A value is trying to be set on a copy of a slice from a DataFrame\n",
            "\n",
            "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n",
            "  return super(DataFrame, self).rename(**kwargs)\n"
          ],
          "name": "stderr"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "V_l0zpLyqtw3",
        "colab_type": "code",
        "outputId": "ed863f96-16d2-46cb-ce2d-dce4459a332a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 311
        }
      },
      "source": [
        "df.head(2)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>uid</th>\n",
              "      <th>iid</th>\n",
              "      <th>rui</th>\n",
              "      <th>est</th>\n",
              "      <th>details</th>\n",
              "      <th>Iu</th>\n",
              "      <th>Ui</th>\n",
              "      <th>err</th>\n",
              "      <th>user_id</th>\n",
              "      <th>rating</th>\n",
              "      <th>title</th>\n",
              "      <th>genre_unknown</th>\n",
              "      <th>Action</th>\n",
              "      <th>Adventure</th>\n",
              "      <th>Animation</th>\n",
              "      <th>Children</th>\n",
              "      <th>Comedy</th>\n",
              "      <th>Crime</th>\n",
              "      <th>Documentary</th>\n",
              "      <th>Drama</th>\n",
              "      <th>Fantasy</th>\n",
              "      <th>Film-Noir</th>\n",
              "      <th>Horror</th>\n",
              "      <th>Musical</th>\n",
              "      <th>Mystery</th>\n",
              "      <th>Romance</th>\n",
              "      <th>Sci-Fi</th>\n",
              "      <th>Thriller</th>\n",
              "      <th>War</th>\n",
              "      <th>Western</th>\n",
              "      <th>year</th>\n",
              "      <th>genre</th>\n",
              "      <th>all_genres</th>\n",
              "      <th>age</th>\n",
              "      <th>sex</th>\n",
              "      <th>occupation</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>718</td>\n",
              "      <td>356</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.818739</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>47</td>\n",
              "      <td>172</td>\n",
              "      <td>0.181261</td>\n",
              "      <td>153</td>\n",
              "      <td>4.0</td>\n",
              "      <td>One Flew Over the Cuckoo's Nest (1975)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1975</td>\n",
              "      <td>Drama</td>\n",
              "      <td>Drama</td>\n",
              "      <td>25</td>\n",
              "      <td>M</td>\n",
              "      <td>student</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>718</td>\n",
              "      <td>356</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.818739</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>47</td>\n",
              "      <td>172</td>\n",
              "      <td>0.181261</td>\n",
              "      <td>295</td>\n",
              "      <td>5.0</td>\n",
              "      <td>One Flew Over the Cuckoo's Nest (1975)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1975</td>\n",
              "      <td>Drama</td>\n",
              "      <td>Drama</td>\n",
              "      <td>43</td>\n",
              "      <td>F</td>\n",
              "      <td>administrator</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   uid  iid  rui       est  ... all_genres  age  sex     occupation\n",
              "0  718  356  4.0  3.818739  ...      Drama   25    M        student\n",
              "1  718  356  4.0  3.818739  ...      Drama   43    F  administrator\n",
              "\n",
              "[2 rows x 36 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 27
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "trq56PHheR0R",
        "colab_type": "code",
        "outputId": "caa60422-0bc9-465d-e694-99feffe78a2f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 300
        }
      },
      "source": [
        "temp1 = df.loc[:,('title', 'err')].groupby('title').mean().sort_values(by = 'err')\n",
        "temp2 = df['title'].value_counts()\n",
        "temp3 = temp1.join(temp2, on = 'title',  how='left', lsuffix='_caller')\n",
        "temp3.rename(columns={'err': 'error_rate', 'title': 'number_of_ratings'}, inplace=True)\n",
        "\n",
        "sns.scatterplot(data = temp3, x ='error_rate' , y = 'number_of_ratings', alpha= 0.6)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<matplotlib.axes._subplots.AxesSubplot at 0x7f5459c7e4a8>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 28
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YMUPPg2Vyi6a",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "temp1 = movies.loc[:, ('title', 'Action', 'Adventure', 'Animation', 'Children',\n",
        "       'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir',\n",
        "       'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War',\n",
        "       'Western')]\n",
        "\n",
        "temp4 = temp3.merge(temp1, on = 'title',  how='left')\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "U--erGRLzA4k",
        "colab_type": "code",
        "outputId": "bede63aa-24aa-4e01-f456-7771aba95891",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 470
        }
      },
      "source": [
        "df.corr().sort_values(by = 'err').loc[:,'err']"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "rui                  -0.246602\n",
              "est                  -0.104338\n",
              "Ui                   -0.026051\n",
              "Thriller             -0.024476\n",
              "Iu                   -0.016871\n",
              "Drama                -0.013710\n",
              "Film-Noir            -0.011290\n",
              "Western              -0.008030\n",
              "Action               -0.007207\n",
              "Mystery              -0.006424\n",
              "War                  -0.006029\n",
              "Fantasy              -0.001258\n",
              "Adventure            -0.000309\n",
              "Crime                 0.000189\n",
              "Animation             0.000416\n",
              "Romance               0.003093\n",
              "Children              0.004586\n",
              "Sci-Fi                0.010299\n",
              "Comedy                0.016062\n",
              "iid_caller            0.016162\n",
              "Documentary           0.018597\n",
              "Musical               0.019215\n",
              "Horror                0.019351\n",
              "err                   1.000000\n",
              "video_release_date         NaN\n",
              "genre_unknown              NaN\n",
              "Name: err, dtype: float64"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 185
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "7RjeNy-YPRpx",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# best_predictions\n",
        "df.sort_values(by='err')[-10:]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0bW4Bm2vkbkN",
        "colab_type": "code",
        "outputId": "da6f7405-e4fb-4463-8fe0-ad18fbd9f925",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 343
        }
      },
      "source": [
        "#worst_predictions\n",
        "df.sort_values(by='err')[:10]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>uid</th>\n",
              "      <th>iid</th>\n",
              "      <th>rui</th>\n",
              "      <th>est</th>\n",
              "      <th>details</th>\n",
              "      <th>Iu</th>\n",
              "      <th>Ui</th>\n",
              "      <th>err</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>6976</th>\n",
              "      <td>238</td>\n",
              "      <td>189</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.457731</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>118</td>\n",
              "      <td>94</td>\n",
              "      <td>3.457731</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10984</th>\n",
              "      <td>278</td>\n",
              "      <td>63</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.462070</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>266</td>\n",
              "      <td>211</td>\n",
              "      <td>3.462070</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7708</th>\n",
              "      <td>704</td>\n",
              "      <td>190</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.483769</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>81</td>\n",
              "      <td>199</td>\n",
              "      <td>3.483769</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>18447</th>\n",
              "      <td>776</td>\n",
              "      <td>99</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.535799</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>29</td>\n",
              "      <td>380</td>\n",
              "      <td>3.535799</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>15271</th>\n",
              "      <td>433</td>\n",
              "      <td>8</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.603552</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>31</td>\n",
              "      <td>216</td>\n",
              "      <td>3.603552</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3243</th>\n",
              "      <td>587</td>\n",
              "      <td>97</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.608203</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>155</td>\n",
              "      <td>293</td>\n",
              "      <td>3.608203</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20290</th>\n",
              "      <td>619</td>\n",
              "      <td>99</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.617288</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>73</td>\n",
              "      <td>380</td>\n",
              "      <td>3.617288</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6130</th>\n",
              "      <td>711</td>\n",
              "      <td>135</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.653913</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>107</td>\n",
              "      <td>81</td>\n",
              "      <td>3.653913</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10157</th>\n",
              "      <td>404</td>\n",
              "      <td>574</td>\n",
              "      <td>5.0</td>\n",
              "      <td>1.254117</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>364</td>\n",
              "      <td>37</td>\n",
              "      <td>3.745883</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>17096</th>\n",
              "      <td>238</td>\n",
              "      <td>317</td>\n",
              "      <td>1.0</td>\n",
              "      <td>4.774659</td>\n",
              "      <td>{'was_impossible': False}</td>\n",
              "      <td>118</td>\n",
              "      <td>223</td>\n",
              "      <td>3.774659</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "       uid  iid  rui       est                    details   Iu   Ui       err\n",
              "6976   238  189  1.0  4.457731  {'was_impossible': False}  118   94  3.457731\n",
              "10984  278   63  1.0  4.462070  {'was_impossible': False}  266  211  3.462070\n",
              "7708   704  190  1.0  4.483769  {'was_impossible': False}   81  199  3.483769\n",
              "18447  776   99  1.0  4.535799  {'was_impossible': False}   29  380  3.535799\n",
              "15271  433    8  1.0  4.603552  {'was_impossible': False}   31  216  3.603552\n",
              "3243   587   97  1.0  4.608203  {'was_impossible': False}  155  293  3.608203\n",
              "20290  619   99  1.0  4.617288  {'was_impossible': False}   73  380  3.617288\n",
              "6130   711  135  1.0  4.653913  {'was_impossible': False}  107   81  3.653913\n",
              "10157  404  574  5.0  1.254117  {'was_impossible': False}  364   37  3.745883\n",
              "17096  238  317  1.0  4.774659  {'was_impossible': False}  118  223  3.774659"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 87
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "cOREe58u26l_",
        "colab_type": "code",
        "outputId": "c29489a7-5c59-4e71-e457-7f7933defaf1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 442
        }
      },
      "source": [
        "df.hist('err', bins = 30)\n",
        "\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "error",
          "ename": "AttributeError",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-40-2721ae9c8fb0>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'err'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbins\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m30\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmedian\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mAttributeError\u001b[0m: 'numpy.ndarray' object has no attribute 'median'"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "yewhLnOdDS_g",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# next steps:\n",
        "# merge with movie title\n",
        "# try to understand most predictive movies\n",
        "# try to understand number on rating per movie as a threshhold\n",
        "# bulid mini recommandation system\n",
        "\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7uaO0CwEicnV",
        "colab_type": "text"
      },
      "source": [
        "**Dean:**  That looks great! \n",
        "\n",
        "I think we should \"bucket\" the errors accourding to \n",
        "the number of ratings, or the number of users.\n",
        "\n",
        "similar code I've done in another project (my home-test for a job)\n",
        "(RUL is the target label)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SdbppJj0seHC",
        "colab_type": "text"
      },
      "source": [
        "# Collaborative Filtering - Sparse MF algorithm (Andrew Ng)\n",
        "implemented by us from the Coursera Course"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PHwhGmC5YtGj",
        "colab_type": "text"
      },
      "source": [
        "## Algorithm (sparse MF):"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "qM0C_OLJfAX9",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "pivot = movielens.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot.fillna(0, inplace = True)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YOSfaolgekYN",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def cofiCostFunc(params, Y, R, num_users, num_movies,\n",
        "                      num_features, lambda_=0.0):\n",
        "    \"\"\"\n",
        "    Collaborative filtering cost function.\n",
        "    \n",
        "    Parameters\n",
        "    ----------\n",
        "    params : array_like\n",
        "        The parameters which will be optimized. This is a one\n",
        "        dimensional vector of shape (num_movies x num_users, 1). It is the \n",
        "        concatenation of the feature vectors X and parameters Theta.\n",
        "    \n",
        "    Y : array_like\n",
        "        A matrix of shape (num_movies x num_users) of user ratings of movies.\n",
        "    \n",
        "    R : array_like\n",
        "        A (num_movies x num_users) matrix, where R[i, j] = 1 if the \n",
        "        i-th movie was rated by the j-th user.\n",
        "    \n",
        "    num_users : int\n",
        "        Total number of users.\n",
        "    \n",
        "    num_movies : int\n",
        "        Total number of movies.\n",
        "    \n",
        "    num_features : int\n",
        "        Number of features to learn.\n",
        "    \n",
        "    lambda_ : float, optional\n",
        "        The regularization coefficient.\n",
        "    \n",
        "    Returns\n",
        "    -------\n",
        "    J : float\n",
        "        The value of the cost function at the given params.\n",
        "    \n",
        "    grad : array_like\n",
        "        The gradient vector of the cost function at the given params.\n",
        "        grad has a shape (num_movies x num_users, 1)\n",
        "    \n",
        "    Instructions\n",
        "    ------------\n",
        "    Compute the cost function and gradient for collaborative filtering.\n",
        "    Concretely, you should first implement the cost function (without\n",
        "    regularization) and make sure it is matches our costs. After that,\n",
        "    you should implement thegradient and use the checkCostFunction routine \n",
        "    to check that the gradient is correct. Finally, you should implement\n",
        "    regularization.\n",
        "    \n",
        "    Notes\n",
        "    -----\n",
        "    - The input params will be unraveled into the two matrices:\n",
        "        X : (num_movies  x num_features) matrix of movie features >>>   X (m * p)\n",
        "        Theta : (num_users  x num_features) matrix of user features >>> Theta (n * p)\n",
        "\n",
        "    - You should set the following variables correctly:\n",
        "\n",
        "        X_grad : (num_movies x num_features) matrix, containing the \n",
        "                 partial derivatives w.r.t. to each element of X\n",
        "        Theta_grad : (num_users x num_features) matrix, containing the \n",
        "                     partial derivatives w.r.t. to each element of Theta\n",
        "\n",
        "    - The returned gradient will be the concatenation of the raveled \n",
        "      gradients X_grad and Theta_grad.\n",
        "    \"\"\"\n",
        "    # Unfold the X and Theta matrices from params\n",
        "    X = params[:num_movies*num_features].reshape(num_movies, num_features) # (m * p)\n",
        "    Theta = params[num_movies*num_features:].reshape(num_users, num_features) # (n * p)\n",
        "\n",
        "    # You need to return the following values correctly\n",
        "    J = 0\n",
        "    X_grad = np.zeros(X.shape)\n",
        "    Theta_grad = np.zeros(Theta.shape)\n",
        "\n",
        "    # ====================== YOUR CODE HERE ======================\n",
        "\n",
        "    M = np.dot(X, Theta.T)\n",
        "    Z = np.square(np.multiply(R , M) - Y) # (m * n) \n",
        "    J = 0.5 * np.sum(Z)\n",
        "    \n",
        "    Z2 = np.multiply(R , M) - Y #(m * n) \n",
        "\n",
        "    X_grad = np.dot(Z2,Theta) + lambda_* X  # (m*n)dot(n*p)\n",
        "    Theta_grad = np.dot(Z2.T,X) + lambda_* Theta # (m*n)dot(m*p)\n",
        "        \n",
        "    J +=  0.5*lambda_*(np.sum(np.square(X))+np.sum(np.square(Theta)))\n",
        "    # =============================================================\n",
        "    \n",
        "    grad = np.concatenate([X_grad.ravel(), Theta_grad.ravel()])\n",
        "    return J, grad"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-dyxKJ1ZgWGd",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def normalizeRatings(Y, R):\n",
        "    \"\"\"\n",
        "    Preprocess data by subtracting mean rating for every movie (every row).\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    Y : array_like\n",
        "        The user ratings for all movies. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    R : array_like\n",
        "        Indicator matrix for movies rated by users. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    Ynorm : array_like\n",
        "        A matrix of same shape as Y, after mean normalization.\n",
        "\n",
        "    Ymean : array_like\n",
        "        A vector of shape (num_movies, ) containing the mean rating for each movie.\n",
        "    \"\"\"\n",
        "    m, n = Y.shape\n",
        "    Ymean = np.zeros(m)\n",
        "    Ynorm = np.zeros(Y.shape)\n",
        "\n",
        "    for i in range(m):\n",
        "        idx = R[i, :] == 1\n",
        "        Ymean[i] = np.mean(Y[i, idx])\n",
        "        Ynorm[i, idx] = Y[i, idx] - Ymean[i]\n",
        "\n",
        "    return Ynorm, Ymean\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Ab3m2EaLfa6E",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#  Useful Values\n",
        "num_movies, num_users = pivot.shape\n",
        "num_features = 10\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "yEtPxaxVhQDD",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by \n",
        "#  943 users\n",
        "\n",
        "Y = pivot.values\n",
        "\n",
        "#  R is a 1682x943 matrix, where R(i,j) = 1 if and only if user j gave a\n",
        "#  rating to movie i\n",
        "\n",
        "idx = np.where(pivot>0)\n",
        "\n",
        "R = np.zeros_like(Y)\n",
        "\n",
        "R[idx] = 1\n",
        "\n",
        "#  X : (num_movies  x num_features) matrix of movie features >>>   X = (1682 X p)\n",
        "#  Theta : (num_users  x num_features) matrix of user features >>> Theta = (943 X p)\n",
        "\n",
        "# Set Initial Parameters (Theta, X)\n",
        "X = np.random.randn(num_movies, num_features)\n",
        "Theta = np.random.randn(num_users, num_features)\n",
        "\n",
        "initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y6U11RLtl_fc",
        "colab_type": "text"
      },
      "source": [
        "**Next - try to optimize the training parameters, and use test-train split**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "isnKFU1XfvHI",
        "colab_type": "code",
        "outputId": "76bfa50d-a4df-4f32-e8af-240e1b7fda4a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "from scipy import optimize\n",
        "\n",
        "def trainRecommender(Y, R, X, Theta, n_users = 943):\n",
        "    \n",
        "    Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "    # Set options for scipy.optimize.minimize\n",
        "    options = {'maxiter': 100}\n",
        "\n",
        "    # Set Regularization\n",
        "    lambda_ = 10\n",
        "    res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                                   num_movies, num_features, lambda_),\n",
        "                            initial_parameters,\n",
        "                            method='TNC',\n",
        "                            jac=True,\n",
        "                            options=options)\n",
        "    theta = res.x\n",
        "\n",
        "    # Unfold the returned theta back into U and W\n",
        "    X = theta[:num_movies*num_features].reshape(num_movies, num_features)\n",
        "    Theta = theta[num_movies*num_features:].reshape(num_users, num_features)\n",
        "\n",
        "    print('Recommender system learning completed.')\n",
        "    \n",
        "    return (X, Theta, Ynorm, Ymean)\n",
        "    \n",
        "X, Theta, Ynorm, Ymean = trainRecommender(Y, R, X, Theta)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Recommender system learning completed.\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ClAb0O3xi6lF",
        "colab_type": "code",
        "outputId": "b7301d7e-3b02-4148-8d59-e3aa707f8d5c",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 251
        }
      },
      "source": [
        "#Predictions:\n",
        "p = np.dot(X, Theta.T)\n",
        "\n",
        "#Adding back the mean of every movie, Ymean\n",
        "predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "pd.DataFrame(predictions).head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>0</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>3</th>\n",
              "      <th>4</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>8</th>\n",
              "      <th>9</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>12</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>17</th>\n",
              "      <th>18</th>\n",
              "      <th>19</th>\n",
              "      <th>20</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>26</th>\n",
              "      <th>27</th>\n",
              "      <th>28</th>\n",
              "      <th>29</th>\n",
              "      <th>30</th>\n",
              "      <th>31</th>\n",
              "      <th>32</th>\n",
              "      <th>33</th>\n",
              "      <th>34</th>\n",
              "      <th>35</th>\n",
              "      <th>36</th>\n",
              "      <th>37</th>\n",
              "      <th>38</th>\n",
              "      <th>39</th>\n",
              "      <th>...</th>\n",
              "      <th>570</th>\n",
              "      <th>571</th>\n",
              "      <th>572</th>\n",
              "      <th>573</th>\n",
              "      <th>574</th>\n",
              "      <th>575</th>\n",
              "      <th>576</th>\n",
              "      <th>577</th>\n",
              "      <th>578</th>\n",
              "      <th>579</th>\n",
              "      <th>580</th>\n",
              "      <th>581</th>\n",
              "      <th>582</th>\n",
              "      <th>583</th>\n",
              "      <th>584</th>\n",
              "      <th>585</th>\n",
              "      <th>586</th>\n",
              "      <th>587</th>\n",
              "      <th>588</th>\n",
              "      <th>589</th>\n",
              "      <th>590</th>\n",
              "      <th>591</th>\n",
              "      <th>592</th>\n",
              "      <th>593</th>\n",
              "      <th>594</th>\n",
              "      <th>595</th>\n",
              "      <th>596</th>\n",
              "      <th>597</th>\n",
              "      <th>598</th>\n",
              "      <th>599</th>\n",
              "      <th>600</th>\n",
              "      <th>601</th>\n",
              "      <th>602</th>\n",
              "      <th>603</th>\n",
              "      <th>604</th>\n",
              "      <th>605</th>\n",
              "      <th>606</th>\n",
              "      <th>607</th>\n",
              "      <th>608</th>\n",
              "      <th>609</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>5.020299</td>\n",
              "      <td>3.313386</td>\n",
              "      <td>4.323094</td>\n",
              "      <td>3.987173</td>\n",
              "      <td>3.913902</td>\n",
              "      <td>4.074329</td>\n",
              "      <td>4.517856</td>\n",
              "      <td>4.133638</td>\n",
              "      <td>4.253894</td>\n",
              "      <td>4.281907</td>\n",
              "      <td>4.364387</td>\n",
              "      <td>3.790754</td>\n",
              "      <td>4.196639</td>\n",
              "      <td>3.899172</td>\n",
              "      <td>3.191059</td>\n",
              "      <td>3.264718</td>\n",
              "      <td>3.714995</td>\n",
              "      <td>3.620100</td>\n",
              "      <td>4.297834</td>\n",
              "      <td>3.839726</td>\n",
              "      <td>3.975566</td>\n",
              "      <td>3.887991</td>\n",
              "      <td>4.279534</td>\n",
              "      <td>4.280526</td>\n",
              "      <td>3.823305</td>\n",
              "      <td>3.844617</td>\n",
              "      <td>4.873452</td>\n",
              "      <td>3.843786</td>\n",
              "      <td>4.160640</td>\n",
              "      <td>4.066453</td>\n",
              "      <td>3.867474</td>\n",
              "      <td>3.436198</td>\n",
              "      <td>4.053843</td>\n",
              "      <td>4.153207</td>\n",
              "      <td>4.064059</td>\n",
              "      <td>3.671564</td>\n",
              "      <td>3.581617</td>\n",
              "      <td>3.191378</td>\n",
              "      <td>3.474342</td>\n",
              "      <td>3.978907</td>\n",
              "      <td>...</td>\n",
              "      <td>3.582514</td>\n",
              "      <td>4.186750</td>\n",
              "      <td>3.935984</td>\n",
              "      <td>4.488017</td>\n",
              "      <td>3.850634</td>\n",
              "      <td>2.927744</td>\n",
              "      <td>4.339079</td>\n",
              "      <td>4.040313</td>\n",
              "      <td>4.232621</td>\n",
              "      <td>3.917539</td>\n",
              "      <td>4.076006</td>\n",
              "      <td>3.713674</td>\n",
              "      <td>4.335136</td>\n",
              "      <td>3.731457</td>\n",
              "      <td>2.550273</td>\n",
              "      <td>3.750893</td>\n",
              "      <td>3.695468</td>\n",
              "      <td>4.210062</td>\n",
              "      <td>3.958515</td>\n",
              "      <td>4.444233</td>\n",
              "      <td>3.695653</td>\n",
              "      <td>3.083785</td>\n",
              "      <td>3.412366</td>\n",
              "      <td>4.063433</td>\n",
              "      <td>3.821545</td>\n",
              "      <td>4.071047</td>\n",
              "      <td>4.051008</td>\n",
              "      <td>4.202909</td>\n",
              "      <td>1.386896</td>\n",
              "      <td>4.019180</td>\n",
              "      <td>4.169439</td>\n",
              "      <td>3.026164</td>\n",
              "      <td>4.035158</td>\n",
              "      <td>4.795028</td>\n",
              "      <td>3.449409</td>\n",
              "      <td>4.733999</td>\n",
              "      <td>4.365159</td>\n",
              "      <td>4.337135</td>\n",
              "      <td>4.218139</td>\n",
              "      <td>4.318423</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>3.929422</td>\n",
              "      <td>3.570193</td>\n",
              "      <td>3.864681</td>\n",
              "      <td>3.457279</td>\n",
              "      <td>3.409461</td>\n",
              "      <td>3.586891</td>\n",
              "      <td>3.348663</td>\n",
              "      <td>3.896000</td>\n",
              "      <td>3.685751</td>\n",
              "      <td>3.690572</td>\n",
              "      <td>3.678891</td>\n",
              "      <td>3.326754</td>\n",
              "      <td>3.761402</td>\n",
              "      <td>3.426266</td>\n",
              "      <td>3.453264</td>\n",
              "      <td>3.608644</td>\n",
              "      <td>3.729219</td>\n",
              "      <td>3.381391</td>\n",
              "      <td>3.924233</td>\n",
              "      <td>3.640739</td>\n",
              "      <td>3.472207</td>\n",
              "      <td>3.483611</td>\n",
              "      <td>4.048776</td>\n",
              "      <td>3.731203</td>\n",
              "      <td>3.460987</td>\n",
              "      <td>3.341881</td>\n",
              "      <td>4.149577</td>\n",
              "      <td>3.549399</td>\n",
              "      <td>3.523410</td>\n",
              "      <td>3.625951</td>\n",
              "      <td>3.476551</td>\n",
              "      <td>3.360178</td>\n",
              "      <td>3.526379</td>\n",
              "      <td>3.693882</td>\n",
              "      <td>3.609268</td>\n",
              "      <td>3.487034</td>\n",
              "      <td>3.191409</td>\n",
              "      <td>2.932076</td>\n",
              "      <td>3.318379</td>\n",
              "      <td>3.543332</td>\n",
              "      <td>...</td>\n",
              "      <td>3.070904</td>\n",
              "      <td>3.433349</td>\n",
              "      <td>3.467022</td>\n",
              "      <td>3.822643</td>\n",
              "      <td>3.466651</td>\n",
              "      <td>4.640702</td>\n",
              "      <td>3.801923</td>\n",
              "      <td>3.215736</td>\n",
              "      <td>3.649092</td>\n",
              "      <td>3.599479</td>\n",
              "      <td>3.602419</td>\n",
              "      <td>3.739929</td>\n",
              "      <td>3.605222</td>\n",
              "      <td>3.274921</td>\n",
              "      <td>3.015177</td>\n",
              "      <td>3.565423</td>\n",
              "      <td>3.346617</td>\n",
              "      <td>3.701964</td>\n",
              "      <td>3.392044</td>\n",
              "      <td>3.969816</td>\n",
              "      <td>3.348265</td>\n",
              "      <td>3.595728</td>\n",
              "      <td>3.089313</td>\n",
              "      <td>3.435075</td>\n",
              "      <td>3.476122</td>\n",
              "      <td>3.671883</td>\n",
              "      <td>3.556223</td>\n",
              "      <td>3.637356</td>\n",
              "      <td>3.220989</td>\n",
              "      <td>3.626374</td>\n",
              "      <td>3.670833</td>\n",
              "      <td>3.865828</td>\n",
              "      <td>3.567350</td>\n",
              "      <td>3.964931</td>\n",
              "      <td>3.487165</td>\n",
              "      <td>3.852500</td>\n",
              "      <td>3.580475</td>\n",
              "      <td>3.704033</td>\n",
              "      <td>3.578813</td>\n",
              "      <td>3.666632</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>3.129026</td>\n",
              "      <td>2.748832</td>\n",
              "      <td>2.961807</td>\n",
              "      <td>2.773018</td>\n",
              "      <td>2.764006</td>\n",
              "      <td>2.938637</td>\n",
              "      <td>2.847023</td>\n",
              "      <td>2.966059</td>\n",
              "      <td>2.864563</td>\n",
              "      <td>2.898272</td>\n",
              "      <td>2.896631</td>\n",
              "      <td>2.699789</td>\n",
              "      <td>2.901646</td>\n",
              "      <td>2.747663</td>\n",
              "      <td>2.566298</td>\n",
              "      <td>2.739485</td>\n",
              "      <td>2.798066</td>\n",
              "      <td>2.738720</td>\n",
              "      <td>2.928080</td>\n",
              "      <td>2.797058</td>\n",
              "      <td>2.766440</td>\n",
              "      <td>2.762380</td>\n",
              "      <td>3.052874</td>\n",
              "      <td>2.960913</td>\n",
              "      <td>2.753587</td>\n",
              "      <td>2.730580</td>\n",
              "      <td>3.040122</td>\n",
              "      <td>2.805719</td>\n",
              "      <td>2.827383</td>\n",
              "      <td>2.936110</td>\n",
              "      <td>2.782597</td>\n",
              "      <td>2.667856</td>\n",
              "      <td>2.820506</td>\n",
              "      <td>2.932041</td>\n",
              "      <td>2.845586</td>\n",
              "      <td>2.814535</td>\n",
              "      <td>2.674119</td>\n",
              "      <td>2.478634</td>\n",
              "      <td>2.656071</td>\n",
              "      <td>2.823974</td>\n",
              "      <td>...</td>\n",
              "      <td>2.664983</td>\n",
              "      <td>2.800837</td>\n",
              "      <td>2.800231</td>\n",
              "      <td>2.916679</td>\n",
              "      <td>2.807003</td>\n",
              "      <td>2.917747</td>\n",
              "      <td>2.916869</td>\n",
              "      <td>2.713406</td>\n",
              "      <td>2.865038</td>\n",
              "      <td>2.860016</td>\n",
              "      <td>2.855670</td>\n",
              "      <td>2.844832</td>\n",
              "      <td>2.872473</td>\n",
              "      <td>2.721855</td>\n",
              "      <td>2.424050</td>\n",
              "      <td>2.807479</td>\n",
              "      <td>2.733116</td>\n",
              "      <td>2.873219</td>\n",
              "      <td>2.761861</td>\n",
              "      <td>3.010993</td>\n",
              "      <td>2.626121</td>\n",
              "      <td>2.787791</td>\n",
              "      <td>2.755545</td>\n",
              "      <td>2.826865</td>\n",
              "      <td>2.794629</td>\n",
              "      <td>2.847007</td>\n",
              "      <td>2.809259</td>\n",
              "      <td>2.839752</td>\n",
              "      <td>2.503528</td>\n",
              "      <td>2.791656</td>\n",
              "      <td>2.840342</td>\n",
              "      <td>2.575664</td>\n",
              "      <td>2.838985</td>\n",
              "      <td>3.115571</td>\n",
              "      <td>2.669794</td>\n",
              "      <td>2.980200</td>\n",
              "      <td>2.853196</td>\n",
              "      <td>2.909783</td>\n",
              "      <td>2.814738</td>\n",
              "      <td>2.982867</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>4.005954</td>\n",
              "      <td>4.009078</td>\n",
              "      <td>3.998279</td>\n",
              "      <td>3.991040</td>\n",
              "      <td>3.999149</td>\n",
              "      <td>3.990523</td>\n",
              "      <td>4.007358</td>\n",
              "      <td>4.007518</td>\n",
              "      <td>3.989548</td>\n",
              "      <td>4.002851</td>\n",
              "      <td>3.989087</td>\n",
              "      <td>3.997217</td>\n",
              "      <td>4.003385</td>\n",
              "      <td>3.995898</td>\n",
              "      <td>4.022425</td>\n",
              "      <td>3.996959</td>\n",
              "      <td>3.985582</td>\n",
              "      <td>4.012204</td>\n",
              "      <td>3.995895</td>\n",
              "      <td>4.008483</td>\n",
              "      <td>4.000195</td>\n",
              "      <td>3.998040</td>\n",
              "      <td>4.001890</td>\n",
              "      <td>3.999772</td>\n",
              "      <td>3.999738</td>\n",
              "      <td>4.001928</td>\n",
              "      <td>3.967038</td>\n",
              "      <td>4.002000</td>\n",
              "      <td>3.998002</td>\n",
              "      <td>4.005492</td>\n",
              "      <td>4.003351</td>\n",
              "      <td>4.000836</td>\n",
              "      <td>3.995973</td>\n",
              "      <td>4.007240</td>\n",
              "      <td>3.994642</td>\n",
              "      <td>4.004184</td>\n",
              "      <td>4.006378</td>\n",
              "      <td>4.010652</td>\n",
              "      <td>4.007136</td>\n",
              "      <td>3.999445</td>\n",
              "      <td>...</td>\n",
              "      <td>4.012717</td>\n",
              "      <td>3.984865</td>\n",
              "      <td>4.001607</td>\n",
              "      <td>3.999254</td>\n",
              "      <td>4.006769</td>\n",
              "      <td>4.033914</td>\n",
              "      <td>3.992156</td>\n",
              "      <td>3.995964</td>\n",
              "      <td>3.997244</td>\n",
              "      <td>4.008534</td>\n",
              "      <td>3.996561</td>\n",
              "      <td>3.993933</td>\n",
              "      <td>3.986538</td>\n",
              "      <td>4.015819</td>\n",
              "      <td>4.025114</td>\n",
              "      <td>4.004547</td>\n",
              "      <td>4.009825</td>\n",
              "      <td>3.997177</td>\n",
              "      <td>4.002261</td>\n",
              "      <td>3.996791</td>\n",
              "      <td>3.993860</td>\n",
              "      <td>4.020742</td>\n",
              "      <td>4.001898</td>\n",
              "      <td>4.002685</td>\n",
              "      <td>4.002015</td>\n",
              "      <td>3.996829</td>\n",
              "      <td>3.996510</td>\n",
              "      <td>3.988397</td>\n",
              "      <td>4.048733</td>\n",
              "      <td>3.996604</td>\n",
              "      <td>3.994150</td>\n",
              "      <td>4.005272</td>\n",
              "      <td>4.001429</td>\n",
              "      <td>4.007324</td>\n",
              "      <td>4.001981</td>\n",
              "      <td>3.990539</td>\n",
              "      <td>3.992849</td>\n",
              "      <td>4.004177</td>\n",
              "      <td>3.988785</td>\n",
              "      <td>4.008005</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>3.509151</td>\n",
              "      <td>3.465003</td>\n",
              "      <td>3.472661</td>\n",
              "      <td>3.497621</td>\n",
              "      <td>3.506482</td>\n",
              "      <td>3.495056</td>\n",
              "      <td>3.491949</td>\n",
              "      <td>3.491623</td>\n",
              "      <td>3.498979</td>\n",
              "      <td>3.486082</td>\n",
              "      <td>3.501954</td>\n",
              "      <td>3.508762</td>\n",
              "      <td>3.475645</td>\n",
              "      <td>3.502875</td>\n",
              "      <td>3.445989</td>\n",
              "      <td>3.544567</td>\n",
              "      <td>3.487336</td>\n",
              "      <td>3.500125</td>\n",
              "      <td>3.493137</td>\n",
              "      <td>3.485605</td>\n",
              "      <td>3.495462</td>\n",
              "      <td>3.503346</td>\n",
              "      <td>3.486078</td>\n",
              "      <td>3.486685</td>\n",
              "      <td>3.505865</td>\n",
              "      <td>3.504402</td>\n",
              "      <td>3.514747</td>\n",
              "      <td>3.501210</td>\n",
              "      <td>3.503119</td>\n",
              "      <td>3.459687</td>\n",
              "      <td>3.493641</td>\n",
              "      <td>3.502479</td>\n",
              "      <td>3.500501</td>\n",
              "      <td>3.493892</td>\n",
              "      <td>3.506011</td>\n",
              "      <td>3.507898</td>\n",
              "      <td>3.501356</td>\n",
              "      <td>3.501843</td>\n",
              "      <td>3.508596</td>\n",
              "      <td>3.496355</td>\n",
              "      <td>...</td>\n",
              "      <td>3.519669</td>\n",
              "      <td>3.507170</td>\n",
              "      <td>3.504657</td>\n",
              "      <td>3.496941</td>\n",
              "      <td>3.501634</td>\n",
              "      <td>3.442125</td>\n",
              "      <td>3.498284</td>\n",
              "      <td>3.482356</td>\n",
              "      <td>3.498254</td>\n",
              "      <td>3.484522</td>\n",
              "      <td>3.505709</td>\n",
              "      <td>3.511452</td>\n",
              "      <td>3.510071</td>\n",
              "      <td>3.491468</td>\n",
              "      <td>3.526008</td>\n",
              "      <td>3.509454</td>\n",
              "      <td>3.497625</td>\n",
              "      <td>3.496265</td>\n",
              "      <td>3.502242</td>\n",
              "      <td>3.503891</td>\n",
              "      <td>3.495692</td>\n",
              "      <td>3.511452</td>\n",
              "      <td>3.534798</td>\n",
              "      <td>3.495926</td>\n",
              "      <td>3.500322</td>\n",
              "      <td>3.493886</td>\n",
              "      <td>3.500382</td>\n",
              "      <td>3.503087</td>\n",
              "      <td>3.511551</td>\n",
              "      <td>3.500811</td>\n",
              "      <td>3.491138</td>\n",
              "      <td>3.509492</td>\n",
              "      <td>3.495829</td>\n",
              "      <td>3.480316</td>\n",
              "      <td>3.501348</td>\n",
              "      <td>3.493724</td>\n",
              "      <td>3.503195</td>\n",
              "      <td>3.496738</td>\n",
              "      <td>3.498454</td>\n",
              "      <td>3.501067</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 610 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "        0         1         2    ...       607       608       609\n",
              "0  5.020299  3.313386  4.323094  ...  4.337135  4.218139  4.318423\n",
              "1  3.929422  3.570193  3.864681  ...  3.704033  3.578813  3.666632\n",
              "2  3.129026  2.748832  2.961807  ...  2.909783  2.814738  2.982867\n",
              "3  4.005954  4.009078  3.998279  ...  4.004177  3.988785  4.008005\n",
              "4  3.509151  3.465003  3.472661  ...  3.496738  3.498454  3.501067\n",
              "\n",
              "[5 rows x 610 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 111
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EfLvsj9ax5Bp",
        "colab_type": "text"
      },
      "source": [
        "## Seeing your own recommendations!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6eIzxcQtx_za",
        "colab_type": "text"
      },
      "source": [
        "Movie list:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HDKM94qTyCAI",
        "colab_type": "code",
        "outputId": "a66aedcb-6c73-4e41-ee25-cc848d946d7d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 662
        }
      },
      "source": [
        "movieList = movies['title']\n",
        "n_m = len(movieList)\n",
        "pd.DataFrame(movieList).tail(20)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>9723</th>\n",
              "      <td>Iron Soldier (2010)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9724</th>\n",
              "      <td>BlacKkKlansman (2018)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9725</th>\n",
              "      <td>The Darkest Minds (2018)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9726</th>\n",
              "      <td>Tilt (2011)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9727</th>\n",
              "      <td>Jeff Ross Roasts the Border (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9728</th>\n",
              "      <td>John From (2015)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9729</th>\n",
              "      <td>Liquid Truth (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9730</th>\n",
              "      <td>Bunny (1998)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9731</th>\n",
              "      <td>Hommage Ã  Zgougou (et salut Ã  Sabine Mamou) ...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9732</th>\n",
              "      <td>Gintama (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9733</th>\n",
              "      <td>Gintama: The Movie (2010)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9734</th>\n",
              "      <td>anohana: The Flower We Saw That Day - The Movi...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9735</th>\n",
              "      <td>Silver Spoon (2014)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9736</th>\n",
              "      <td>Love Live! The School Idol Movie (2015)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9737</th>\n",
              "      <td>Jon Stewart Has Left the Building (2015)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9738</th>\n",
              "      <td>Black Butler: Book of the Atlantic (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9739</th>\n",
              "      <td>No Game No Life: Zero (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9740</th>\n",
              "      <td>Flint (2017)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9741</th>\n",
              "      <td>Bungo Stray Dogs: Dead Apple (2018)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9742</th>\n",
              "      <td>Andrew Dice Clay: Dice Rules (1991)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                                                  title\n",
              "9723                                Iron Soldier (2010)\n",
              "9724                              BlacKkKlansman (2018)\n",
              "9725                           The Darkest Minds (2018)\n",
              "9726                                        Tilt (2011)\n",
              "9727                 Jeff Ross Roasts the Border (2017)\n",
              "9728                                   John From (2015)\n",
              "9729                                Liquid Truth (2017)\n",
              "9730                                       Bunny (1998)\n",
              "9731  Hommage Ã  Zgougou (et salut Ã  Sabine Mamou) ...\n",
              "9732                                     Gintama (2017)\n",
              "9733                          Gintama: The Movie (2010)\n",
              "9734  anohana: The Flower We Saw That Day - The Movi...\n",
              "9735                                Silver Spoon (2014)\n",
              "9736            Love Live! The School Idol Movie (2015)\n",
              "9737           Jon Stewart Has Left the Building (2015)\n",
              "9738          Black Butler: Book of the Atlantic (2017)\n",
              "9739                       No Game No Life: Zero (2017)\n",
              "9740                                       Flint (2017)\n",
              "9741                Bungo Stray Dogs: Dead Apple (2018)\n",
              "9742                Andrew Dice Clay: Dice Rules (1991)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 93
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "D-cUpKR0rBmm",
        "colab_type": "code",
        "outputId": "6bc813a9-7c20-4b43-bb0e-1560dfb4c5af",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 87
        }
      },
      "source": [
        "#Adding our own ratings\n",
        "\n",
        "#  Initialize my ratings\n",
        "my_ratings = np.zeros(n_m)\n",
        "\n",
        "\n",
        "my_ratings[318] = 1\n",
        "my_ratings[253] = 1\n",
        "\n",
        "print('Dean ratings:')\n",
        "print('-----------------')\n",
        "for i in range(len(my_ratings)):\n",
        "    if my_ratings[i] > 0:\n",
        "        print('Rated %d stars: %s' % (my_ratings[i], movieList[i]))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Dean ratings:\n",
            "-----------------\n",
            "Rated 1 stars: Poison Ivy II (1996)\n",
            "Rated 1 stars: I Like It Like That (1994)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "vjZZ9pSnrzGG",
        "colab_type": "code",
        "outputId": "549d330d-f1cf-4ecd-8b56-8c2ee398037f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 355
        }
      },
      "source": [
        "movies.iloc[310:320, ]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>movie_id</th>\n",
              "      <th>title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>310</th>\n",
              "      <td>351</td>\n",
              "      <td>Corrina, Corrina (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>311</th>\n",
              "      <td>352</td>\n",
              "      <td>Crooklyn (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>312</th>\n",
              "      <td>353</td>\n",
              "      <td>Crow, The (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>313</th>\n",
              "      <td>354</td>\n",
              "      <td>Cobb (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>314</th>\n",
              "      <td>355</td>\n",
              "      <td>Flintstones, The (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>315</th>\n",
              "      <td>356</td>\n",
              "      <td>Forrest Gump (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>316</th>\n",
              "      <td>357</td>\n",
              "      <td>Four Weddings and a Funeral (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>317</th>\n",
              "      <td>358</td>\n",
              "      <td>Higher Learning (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>318</th>\n",
              "      <td>359</td>\n",
              "      <td>I Like It Like That (1994)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>319</th>\n",
              "      <td>360</td>\n",
              "      <td>I Love Trouble (1994)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "    movie_id                               title\n",
              "310      351             Corrina, Corrina (1994)\n",
              "311      352                     Crooklyn (1994)\n",
              "312      353                    Crow, The (1994)\n",
              "313      354                         Cobb (1994)\n",
              "314      355             Flintstones, The (1994)\n",
              "315      356                 Forrest Gump (1994)\n",
              "316      357  Four Weddings and a Funeral (1994)\n",
              "317      358              Higher Learning (1995)\n",
              "318      359          I Like It Like That (1994)\n",
              "319      360               I Love Trouble (1994)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 102
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "UBiDcTAyul6h",
        "colab_type": "code",
        "outputId": "0c5632d0-8eda-47a5-94a9-e4914663ada6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "Y.shape, R.shape, X.shape, Theta.shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "((1682, 943), (1682, 943), (1682, 10), (943, 10))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 40
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "8UkIr2mUrfxY",
        "colab_type": "code",
        "outputId": "0ecf77e6-1674-41c6-8891-07a5e509cbe9",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 52
        }
      },
      "source": [
        "# Re-train with new user predictions:\n",
        "\n",
        "Y = pivot.values\n",
        "R = Y > 0\n",
        "\n",
        "print(\"Adding your recommendations!\")\n",
        "Y = np.hstack([my_ratings[:, None], Y])\n",
        "R = np.hstack([(my_ratings > 0)[:, None], R])\n",
        "\n",
        "#  Normalize Ratings\n",
        "Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "#  Useful Values\n",
        "num_movies, num_users = Y.shape\n",
        "num_features = 15\n",
        "\n",
        "# Set Initial Parameters (Theta, X)\n",
        "X = np.random.randn(num_movies, num_features)\n",
        "Theta = np.random.randn(num_users, num_features)\n",
        "\n",
        "initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n",
        "\n",
        "# Set options for scipy.optimize.minimize\n",
        "options = {'maxiter': 100}\n",
        "\n",
        "# Set Regularization\n",
        "lambda_ = 10\n",
        "\n",
        "#Optimizing using Gradient Descent (in scipy)\n",
        "res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                               num_movies, num_features, lambda_),\n",
        "                        initial_parameters,\n",
        "                        method='TNC',\n",
        "                        jac=True,\n",
        "                        options=options)\n",
        "theta = res.x\n",
        "\n",
        "# Unfold the returned theta back into U and W\n",
        "X = theta[:num_movies*num_features].reshape(num_movies, num_features)\n",
        "Theta = theta[num_movies*num_features:].reshape(num_users, num_features)\n",
        "\n",
        "print('Recommender system learning completed.')\n",
        "\n",
        "\n",
        "#Predictions:\n",
        "p = np.dot(X, Theta.T)\n",
        "\n",
        "#Adding back the mean of every movie, Ymean\n",
        "predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "my_predictions = predictions[:,0]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Adding your recommendations!\n",
            "Recommender system learning completed.\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Fr2AKfuGEo9K",
        "colab_type": "code",
        "outputId": "01d4dd1b-5ced-4592-c89c-c7497997623a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 312
        }
      },
      "source": [
        "ix = np.argsort(my_predictions)[::-1]\n",
        "\n",
        "print('Top recommendations for you:')\n",
        "print('----------------------------')\n",
        "for i in range(10):\n",
        "    j = ix[i]\n",
        "    print('Predicting rating %.1f for movie %s' % (my_predictions[j], movieList[j]))\n",
        "\n",
        "print('\\nOriginal ratings provided:')\n",
        "print('--------------------------')\n",
        "for i in range(len(my_ratings)):\n",
        "    if my_ratings[i] > 0:\n",
        "        print('Rated %d for %s' % (my_ratings[i], movieList[i]))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Top recommendations for you:\n",
            "----------------------------\n",
            "Predicting rating 6.3 for movie Night Flier (1997)\n",
            "Predicting rating 5.2 for movie Touch (1997)\n",
            "Predicting rating 5.2 for movie Junior (1994)\n",
            "Predicting rating 5.1 for movie Love Bug, The (1969)\n",
            "Predicting rating 5.1 for movie Star Trek VI: The Undiscovered Country (1991)\n",
            "Predicting rating 5.1 for movie Winnie the Pooh and the Blustery Day (1968)\n",
            "Predicting rating 5.1 for movie Big Squeeze, The (1996)\n",
            "Predicting rating 5.0 for movie Death and the Maiden (1994)\n",
            "Predicting rating 5.0 for movie Deer Hunter, The (1978)\n",
            "Predicting rating 5.0 for movie Late Bloomers (1996)\n",
            "\n",
            "Original ratings provided:\n",
            "--------------------------\n",
            "Rated 1 for Batman & Robin (1997)\n",
            "Rated 1 for Men in Black (1997)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pfyHbQxeisFg",
        "colab_type": "code",
        "outputId": "51ebe1fd-4ccb-4db0-b5d7-a231005a819b",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 381
        }
      },
      "source": [
        "ix = np.argsort(my_predictions)[::-1]\n",
        "\n",
        "print('Top recommendations for you:')\n",
        "print('----------------------------')\n",
        "for i in range(10):\n",
        "    j = ix[i]\n",
        "    print('Predicting rating %.1f for movie %s' % (my_predictions[j], movieList[j]))\n",
        "\n",
        "print('\\nOriginal ratings provided:')\n",
        "print('--------------------------')\n",
        "for i in range(len(my_ratings)):\n",
        "    if my_ratings[i] > 0:\n",
        "        print('Rated %d for %s' % (my_ratings[i], movieList[i]))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Top recommendations for you:\n",
            "----------------------------\n",
            "Predicting rating 5.0 for movie Deer Hunter, The (1978)\n",
            "Predicting rating 5.0 for movie Star Trek VI: The Undiscovered Country (1991)\n",
            "Predicting rating 5.0 for movie Unbearable Lightness of Being, The (1988)\n",
            "Predicting rating 5.0 for movie Conspiracy Theory (1997)\n",
            "Predicting rating 5.0 for movie Junior (1994)\n",
            "Predicting rating 5.0 for movie Farinelli: il castrato (1994)\n",
            "Predicting rating 5.0 for movie Love Bug, The (1969)\n",
            "Predicting rating 5.0 for movie Nightwatch (1997)\n",
            "Predicting rating 5.0 for movie Audrey Rose (1977)\n",
            "Predicting rating 5.0 for movie Big Squeeze, The (1996)\n",
            "\n",
            "Original ratings provided:\n",
            "--------------------------\n",
            "Rated 5 for Return of the Jedi (1983)\n",
            "Rated 5 for 101 Dalmatians (1996)\n",
            "Rated 5 for Austin Powers: International Man of Mystery (1997)\n",
            "Rated 5 for Lost World: Jurassic Park, The (1997)\n",
            "Rated 5 for Batman & Robin (1997)\n",
            "Rated 5 for Men in Black (1997)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HEh5q6BOw8XQ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "Test Predictions\n",
        "\n",
        "N_min = min num of ratings per user\n",
        "M_min = min number of ratings per movie\n",
        "\n",
        "create new matrix based on N_min and M_min\n",
        "\n",
        "TrainSet = for each instance reduce %of|constant from sample (e.g. leave out 5 randim ratings to test predictions)\n",
        "TestSet = predictions left out\n",
        "\n",
        "make prediction on TrainSet\n",
        "calculate RMSE for each user\n",
        "total score = mean of RMSE ?\n",
        "\n",
        "which movies got the lowest RMSE?\n",
        "check number of ratings per movie * RMSE\n",
        "\n",
        "create the UltimateList - 10-15 movie list that can be splited ot Train-Test and will preform "
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "WLTuk2phIGKp",
        "colab_type": "code",
        "outputId": "c379d73a-de67-4806-c743-07e87849b9fb",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 402
        }
      },
      "source": [
        "ratings.iloc[:,:3]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>195</td>\n",
              "      <td>241</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>185</td>\n",
              "      <td>301</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>21</td>\n",
              "      <td>376</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>243</td>\n",
              "      <td>50</td>\n",
              "      <td>2.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>165</td>\n",
              "      <td>345</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>...</th>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99995</th>\n",
              "      <td>879</td>\n",
              "      <td>475</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99996</th>\n",
              "      <td>715</td>\n",
              "      <td>203</td>\n",
              "      <td>5.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99997</th>\n",
              "      <td>275</td>\n",
              "      <td>1089</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99998</th>\n",
              "      <td>12</td>\n",
              "      <td>224</td>\n",
              "      <td>2.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99999</th>\n",
              "      <td>11</td>\n",
              "      <td>202</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>100000 rows × 3 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "      user_id movie_id  rating\n",
              "0         195      241   3.000\n",
              "1         185      301   3.000\n",
              "2          21      376   1.000\n",
              "3         243       50   2.000\n",
              "4         165      345   1.000\n",
              "...       ...      ...     ...\n",
              "99995     879      475   3.000\n",
              "99996     715      203   5.000\n",
              "99997     275     1089   1.000\n",
              "99998      12      224   2.000\n",
              "99999      11      202   3.000\n",
              "\n",
              "[100000 rows x 3 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 15
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ej1Ug9YnIj4n",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "from scipy.sparse import csr_matrix\n",
        "\n",
        "# pivot ratings into movie features\n",
        "df_movie_features = ratings.iloc[:,:3].pivot(\n",
        "    index='movie_id',\n",
        "    columns='user_id',\n",
        "    values='rating'\n",
        ").fillna(0)\n",
        "# convert dataframe of movie features to scipy sparse matrix\n",
        "mat_movie_features = csr_matrix(df_movie_features.values)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZN3vbJbiKSdO",
        "colab_type": "code",
        "outputId": "f12ec58f-75cc-499e-b938-5a8dc6f00af1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 162
        }
      },
      "source": [
        "reader = Reader(rating_scale=(1, 5))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "error",
          "ename": "NameError",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-25-4097a878456e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mreader\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mReader\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrating_scale\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mNameError\u001b[0m: name 'Reader' is not defined"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "H7npVHr6O8_5",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "8ILhyBC-fJwK",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1pfhnZ9tuKqP",
        "colab_type": "text"
      },
      "source": [
        "## Train-test splitting, Evaluation\n",
        "We implemented a unique way to split the data and calculate MSE."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "9CMimleIm8xp"
      },
      "source": [
        "### Loading U1_base and U2_train data:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Daa9BTwxm8xs",
        "colab": {}
      },
      "source": [
        "# Load each data set (users, movies, and ratings).\n",
        "ratings_cols = ['user_id', 'movie_id', 'rating', 'unix_timestamp']\n",
        "\n",
        "train_df = pd.read_csv(\n",
        "    'ml-100k/ua.base', sep='\\t', names=ratings_cols, encoding='latin-1')\n",
        "\n",
        "test_df = pd.read_csv(\n",
        "    'ml-100k/ua.test', sep='\\t', names=ratings_cols, encoding='latin-1')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "xOZJJBzJoOtD",
        "colab_type": "code",
        "outputId": "f24ffca7-ee54-468f-b294-fd3ac6ced008",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 434
        }
      },
      "source": [
        "movielens.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "      <th>unix_timestamp</th>\n",
              "      <th>title</th>\n",
              "      <th>release_date</th>\n",
              "      <th>video_release_date</th>\n",
              "      <th>imdb_url</th>\n",
              "      <th>genre_unknown</th>\n",
              "      <th>Action</th>\n",
              "      <th>Adventure</th>\n",
              "      <th>Animation</th>\n",
              "      <th>Children</th>\n",
              "      <th>Comedy</th>\n",
              "      <th>Crime</th>\n",
              "      <th>Documentary</th>\n",
              "      <th>Drama</th>\n",
              "      <th>Fantasy</th>\n",
              "      <th>Film-Noir</th>\n",
              "      <th>Horror</th>\n",
              "      <th>Musical</th>\n",
              "      <th>Mystery</th>\n",
              "      <th>Romance</th>\n",
              "      <th>Sci-Fi</th>\n",
              "      <th>Thriller</th>\n",
              "      <th>War</th>\n",
              "      <th>Western</th>\n",
              "      <th>year</th>\n",
              "      <th>genre</th>\n",
              "      <th>all_genres</th>\n",
              "      <th>age</th>\n",
              "      <th>sex</th>\n",
              "      <th>occupation</th>\n",
              "      <th>zip_code</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>195</td>\n",
              "      <td>241</td>\n",
              "      <td>3.0</td>\n",
              "      <td>881250949</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "      <td>24-Jan-1997</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Kolya%20(1996)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1997</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>195</td>\n",
              "      <td>256</td>\n",
              "      <td>2.0</td>\n",
              "      <td>881251577</td>\n",
              "      <td>Men in Black (1997)</td>\n",
              "      <td>04-Jul-1997</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Men+in+Black+...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1997</td>\n",
              "      <td>Sci-Fi</td>\n",
              "      <td>Action-Adventure-Comedy-Sci-Fi</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>195</td>\n",
              "      <td>110</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251793</td>\n",
              "      <td>Truth About Cats &amp; Dogs, The (1996)</td>\n",
              "      <td>26-Apr-1996</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Truth%20About...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1996</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy-Romance</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>195</td>\n",
              "      <td>24</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251955</td>\n",
              "      <td>Birdcage, The (1996)</td>\n",
              "      <td>08-Mar-1996</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Birdcage,%20T...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1996</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>195</td>\n",
              "      <td>381</td>\n",
              "      <td>4.0</td>\n",
              "      <td>881251843</td>\n",
              "      <td>Adventures of Priscilla, Queen of the Desert, ...</td>\n",
              "      <td>01-Jan-1994</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Adventures%20...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1994</td>\n",
              "      <td>Comedy</td>\n",
              "      <td>Comedy-Drama</td>\n",
              "      <td>49</td>\n",
              "      <td>M</td>\n",
              "      <td>writer</td>\n",
              "      <td>55105</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "  user_id movie_id  rating  unix_timestamp  ... age sex  occupation zip_code\n",
              "0     195      241     3.0       881250949  ...  49   M      writer    55105\n",
              "1     195      256     2.0       881251577  ...  49   M      writer    55105\n",
              "2     195      110     4.0       881251793  ...  49   M      writer    55105\n",
              "3     195       24     4.0       881251955  ...  49   M      writer    55105\n",
              "4     195      381     4.0       881251843  ...  49   M      writer    55105\n",
              "\n",
              "[5 rows x 34 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 13
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0ybdMwVgn9bG",
        "colab_type": "code",
        "outputId": "8da0d4b8-afed-484f-a723-f933d0b89237",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "min_user_clicks = 50\n",
        "filter_users = train_df['user_id'].value_counts() > min_user_clicks\n",
        "filter_users = filter_users[filter_users].index.tolist()\n",
        "\n",
        "df_filtered = train_df[(train_df['user_id'].isin(filter_users))]\n",
        "print('The original data frame shape:\\t{}'.format(train_df.shape))\n",
        "print('The new data frame shape:\\t{}'.format(df_filtered.shape))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "The original data frame shape:\t(90570, 4)\n",
            "The new data frame shape:\t(79476, 4)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "3zbYzOzfpnng",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#Filtering out users from the test set, \n",
        "#that do not exist in the training set (after min_clicks cleaning)\n",
        "idx = list(df_filtered.user_id.unique())\n",
        "test_df['filter'] = False\n",
        "\n",
        "for i, val in test_df.iterrows():\n",
        "    if (test_df.user_id[i] in idx):\n",
        "        test_df.loc[i,'filter']=True\n",
        "        \n",
        "test_df_drop = test_df[test_df['filter']==True]\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "lKwRxPPZ52M2",
        "colab_type": "code",
        "outputId": "f57ab954-979e-4ec7-b0d8-c120f4f64c64",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 217
        }
      },
      "source": [
        "#In addition to the user-cleaning from the test set, \n",
        "# some movies may exist in the test set that were removed in the training set.\n",
        "# Therefore we remove those too.\n",
        "\n",
        "idx = list(df_filtered.movie_id.unique())\n",
        "test_df_drop['filter_movies'] = False\n",
        "\n",
        "for i, val in test_df_drop.iterrows():\n",
        "    if (test_df_drop.movie_id[i] in idx):\n",
        "        test_df_drop.loc[i,'filter_movies']=True\n",
        "        \n",
        "test_df_drop = test_df_drop[test_df_drop['filter_movies']==True]\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:3: SettingWithCopyWarning: \n",
            "A value is trying to be set on a copy of a slice from a DataFrame.\n",
            "Try using .loc[row_indexer,col_indexer] = value instead\n",
            "\n",
            "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n",
            "  This is separate from the ipykernel package so we can avoid doing imports until\n",
            "/usr/local/lib/python3.6/dist-packages/pandas/core/indexing.py:543: SettingWithCopyWarning: \n",
            "A value is trying to be set on a copy of a slice from a DataFrame.\n",
            "Try using .loc[row_indexer,col_indexer] = value instead\n",
            "\n",
            "See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy\n",
            "  self.obj[item] = s\n"
          ],
          "name": "stderr"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "WQ_BD7tR6gjW",
        "colab_type": "code",
        "outputId": "0c658636-58ec-4c78-ee31-bd13f265e7a9",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "test_df_drop.filter_movies.value_counts()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "True    4938\n",
              "Name: filter_movies, dtype: int64"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "PIurTnaym8yC",
        "colab": {}
      },
      "source": [
        "pivot_train = df_filtered.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot_train.fillna(0, inplace = True)\n",
        "\n",
        "pivot_test = test_df_drop.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot_test.fillna(0, inplace = True)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "6b69793e-c615-4026-d362-bb75e43c6ce5",
        "id": "8H9t3hYWm8yM",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 33
        }
      },
      "source": [
        "pivot_train.shape, pivot_test.shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "((1675, 494), (1017, 494))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 20
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "3596c5ca-b18f-444e-ade2-45f40184f4c1",
        "id": "8uIUVwhRm8yT",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 275
        }
      },
      "source": [
        "pivot_test.head(5)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>user_id</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>18</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>26</th>\n",
              "      <th>28</th>\n",
              "      <th>38</th>\n",
              "      <th>42</th>\n",
              "      <th>43</th>\n",
              "      <th>44</th>\n",
              "      <th>48</th>\n",
              "      <th>49</th>\n",
              "      <th>54</th>\n",
              "      <th>56</th>\n",
              "      <th>57</th>\n",
              "      <th>58</th>\n",
              "      <th>59</th>\n",
              "      <th>60</th>\n",
              "      <th>62</th>\n",
              "      <th>63</th>\n",
              "      <th>64</th>\n",
              "      <th>65</th>\n",
              "      <th>69</th>\n",
              "      <th>70</th>\n",
              "      <th>72</th>\n",
              "      <th>73</th>\n",
              "      <th>75</th>\n",
              "      <th>...</th>\n",
              "      <th>877</th>\n",
              "      <th>878</th>\n",
              "      <th>880</th>\n",
              "      <th>881</th>\n",
              "      <th>882</th>\n",
              "      <th>883</th>\n",
              "      <th>885</th>\n",
              "      <th>886</th>\n",
              "      <th>887</th>\n",
              "      <th>889</th>\n",
              "      <th>890</th>\n",
              "      <th>892</th>\n",
              "      <th>894</th>\n",
              "      <th>896</th>\n",
              "      <th>897</th>\n",
              "      <th>899</th>\n",
              "      <th>901</th>\n",
              "      <th>903</th>\n",
              "      <th>907</th>\n",
              "      <th>908</th>\n",
              "      <th>911</th>\n",
              "      <th>913</th>\n",
              "      <th>916</th>\n",
              "      <th>918</th>\n",
              "      <th>919</th>\n",
              "      <th>921</th>\n",
              "      <th>922</th>\n",
              "      <th>923</th>\n",
              "      <th>924</th>\n",
              "      <th>927</th>\n",
              "      <th>930</th>\n",
              "      <th>931</th>\n",
              "      <th>932</th>\n",
              "      <th>933</th>\n",
              "      <th>934</th>\n",
              "      <th>936</th>\n",
              "      <th>938</th>\n",
              "      <th>940</th>\n",
              "      <th>942</th>\n",
              "      <th>943</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie_id</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 494 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "user_id   1    2    5    6    7    10   11   ...  933  934  936  938  940  942  943\n",
              "movie_id                                     ...                                   \n",
              "1         0.0  0.0  4.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "2         0.0  0.0  3.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "3         0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "4         0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "5         0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "\n",
              "[5 rows x 494 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 21
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "a375ce9a-c124-478b-ff29-7b70ab22f50c",
        "id": "L7flk43xm8yY",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 275
        }
      },
      "source": [
        "pivot_train.head(5)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>user_id</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>18</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>26</th>\n",
              "      <th>28</th>\n",
              "      <th>38</th>\n",
              "      <th>42</th>\n",
              "      <th>43</th>\n",
              "      <th>44</th>\n",
              "      <th>48</th>\n",
              "      <th>49</th>\n",
              "      <th>54</th>\n",
              "      <th>56</th>\n",
              "      <th>57</th>\n",
              "      <th>58</th>\n",
              "      <th>59</th>\n",
              "      <th>60</th>\n",
              "      <th>62</th>\n",
              "      <th>63</th>\n",
              "      <th>64</th>\n",
              "      <th>65</th>\n",
              "      <th>69</th>\n",
              "      <th>70</th>\n",
              "      <th>72</th>\n",
              "      <th>73</th>\n",
              "      <th>75</th>\n",
              "      <th>...</th>\n",
              "      <th>877</th>\n",
              "      <th>878</th>\n",
              "      <th>880</th>\n",
              "      <th>881</th>\n",
              "      <th>882</th>\n",
              "      <th>883</th>\n",
              "      <th>885</th>\n",
              "      <th>886</th>\n",
              "      <th>887</th>\n",
              "      <th>889</th>\n",
              "      <th>890</th>\n",
              "      <th>892</th>\n",
              "      <th>894</th>\n",
              "      <th>896</th>\n",
              "      <th>897</th>\n",
              "      <th>899</th>\n",
              "      <th>901</th>\n",
              "      <th>903</th>\n",
              "      <th>907</th>\n",
              "      <th>908</th>\n",
              "      <th>911</th>\n",
              "      <th>913</th>\n",
              "      <th>916</th>\n",
              "      <th>918</th>\n",
              "      <th>919</th>\n",
              "      <th>921</th>\n",
              "      <th>922</th>\n",
              "      <th>923</th>\n",
              "      <th>924</th>\n",
              "      <th>927</th>\n",
              "      <th>930</th>\n",
              "      <th>931</th>\n",
              "      <th>932</th>\n",
              "      <th>933</th>\n",
              "      <th>934</th>\n",
              "      <th>936</th>\n",
              "      <th>938</th>\n",
              "      <th>940</th>\n",
              "      <th>942</th>\n",
              "      <th>943</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie_id</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>5.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 494 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "user_id   1    2    5    6    7    10   11   ...  933  934  936  938  940  942  943\n",
              "movie_id                                     ...                                   \n",
              "1         5.0  4.0  0.0  4.0  0.0  4.0  0.0  ...  3.0  2.0  4.0  4.0  0.0  0.0  0.0\n",
              "2         3.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  4.0  0.0  0.0  0.0  0.0  5.0\n",
              "3         4.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  4.0  0.0  0.0  0.0  0.0\n",
              "4         3.0  0.0  0.0  0.0  5.0  4.0  0.0  ...  3.0  5.0  0.0  0.0  2.0  0.0  0.0\n",
              "5         3.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "\n",
              "[5 rows x 494 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 22
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "e8e6378f-26fc-4b58-8c86-56d77fef0659",
        "id": "GrEst39xm8ye",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "print(\"Train set contains {} ratings\".format(np.sum(np.sum(pivot_train>0))))\n",
        "print(\"Test set contains {} ratings\".format(np.sum(np.sum(pivot_test>0))))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Train set contains 79476 ratings\n",
            "Test set contains 4938 ratings\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "79dd39f5-a6e2-40eb-b2ef-e5df86f51827",
        "id": "NMB_R7S4nWyq",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 33
        }
      },
      "source": [
        "#Checking if users in the test set are included in the train set\n",
        "\n",
        "s_test = set(test_df_drop.user_id)\n",
        "s_train = set(df_filtered.user_id)\n",
        "\n",
        "inter = s_train.intersection(s_test)\n",
        "len(inter), len(s_train)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(494, 494)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 24
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "c65a00e6-cd91-483c-d38f-fe07744c66d1",
        "id": "yweDRXnSnWzJ",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 33
        }
      },
      "source": [
        "#Checking if movies in the test set are included in the train set\n",
        "\n",
        "s_test = set(test_df_drop.movie_id)\n",
        "s_train = set(df_filtered.movie_id)\n",
        "\n",
        "inter = s_test.issubset(s_train)\n",
        "inter, len(s_train), len(s_test)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(True, 1675, 1017)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 25
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wqAAa_8JvpVi",
        "colab_type": "text"
      },
      "source": [
        "### Training the CF algorithm on the train-pivot table, to test it later over the test pivot table:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "27tk9fspvMOz",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "from scipy import optimize\n",
        "\n",
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by 943 users\n",
        "\n",
        "Y = pivot_train.values\n",
        "\n",
        "#  R is a 1682x943 matrix, where R(i,j) = 1 if and only if user j gave a rating to movie i\n",
        "\n",
        "idx = np.where(pivot_train>0)\n",
        "\n",
        "R = np.zeros_like(Y)\n",
        "\n",
        "R[idx] = 1\n",
        "\n",
        "#  Useful Values\n",
        "num_movies, num_users = pivot_train.shape\n",
        "num_features = [5,10,15, 30, 50]\n",
        "# Set Regularization\n",
        "\n",
        "lambda_ = [10, 20, 50, 100]\n",
        "# Set options for scipy.optimize.minimize\n",
        "options = [{'maxiter': 50}, {'maxiter': 100}, {'maxiter': 150}, {'maxiter': 200}, {'maxiter': 300}, {'maxiter': 400}]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "UtE1JD_yVv6b",
        "colab": {}
      },
      "source": [
        "def cofiCostFunc(params, Y, R, num_users, num_movies,\n",
        "                      num_features, lambda_=0.0):\n",
        "    \"\"\"\n",
        "    Collaborative filtering cost function.\n",
        "    \n",
        "    Parameters\n",
        "    ----------\n",
        "    params : array_like\n",
        "        The parameters which will be optimized. This is a one\n",
        "        dimensional vector of shape (num_movies x num_users, 1). It is the \n",
        "        concatenation of the feature vectors X and parameters Theta.\n",
        "    \n",
        "    Y : array_like\n",
        "        A matrix of shape (num_movies x num_users) of user ratings of movies.\n",
        "    \n",
        "    R : array_like\n",
        "        A (num_movies x num_users) matrix, where R[i, j] = 1 if the \n",
        "        i-th movie was rated by the j-th user.\n",
        "    \n",
        "    num_users : int\n",
        "        Total number of users.\n",
        "    \n",
        "    num_movies : int\n",
        "        Total number of movies.\n",
        "    \n",
        "    num_features : int\n",
        "        Number of features to learn.\n",
        "    \n",
        "    lambda_ : float, optional\n",
        "        The regularization coefficient.\n",
        "    \n",
        "    Returns\n",
        "    -------\n",
        "    J : float\n",
        "        The value of the cost function at the given params.\n",
        "    \n",
        "    grad : array_like\n",
        "        The gradient vector of the cost function at the given params.\n",
        "        grad has a shape (num_movies x num_users, 1)\n",
        "    \n",
        "    Instructions\n",
        "    ------------\n",
        "    Compute the cost function and gradient for collaborative filtering.\n",
        "    Concretely, you should first implement the cost function (without\n",
        "    regularization) and make sure it is matches our costs. After that,\n",
        "    you should implement thegradient and use the checkCostFunction routine \n",
        "    to check that the gradient is correct. Finally, you should implement\n",
        "    regularization.\n",
        "    \n",
        "    Notes\n",
        "    -----\n",
        "    - The input params will be unraveled into the two matrices:\n",
        "        X : (num_movies  x num_features) matrix of movie features >>>   X (m * p)\n",
        "        Theta : (num_users  x num_features) matrix of user features >>> Theta (n * p)\n",
        "\n",
        "    - You should set the following variables correctly:\n",
        "\n",
        "        X_grad : (num_movies x num_features) matrix, containing the \n",
        "                 partial derivatives w.r.t. to each element of X\n",
        "        Theta_grad : (num_users x num_features) matrix, containing the \n",
        "                     partial derivatives w.r.t. to each element of Theta\n",
        "\n",
        "    - The returned gradient will be the concatenation of the raveled \n",
        "      gradients X_grad and Theta_grad.\n",
        "    \"\"\"\n",
        "    # Unfold the X and Theta matrices from params\n",
        "    X = params[:num_movies*num_features].reshape(num_movies, num_features) # (m * p)\n",
        "    Theta = params[num_movies*num_features:].reshape(num_users, num_features) # (n * p)\n",
        "\n",
        "    # You need to return the following values correctly\n",
        "    J = 0\n",
        "    X_grad = np.zeros(X.shape)\n",
        "    Theta_grad = np.zeros(Theta.shape)\n",
        "\n",
        "    # ====================== YOUR CODE HERE ======================\n",
        "\n",
        "    M = np.dot(X, Theta.T)\n",
        "    Z = np.square(np.multiply(R , M) - Y) # (m * n) \n",
        "    J = 0.5 * np.sum(Z)\n",
        "    \n",
        "    Z2 = np.multiply(R , M) - Y #(m * n) \n",
        "\n",
        "    X_grad = np.dot(Z2,Theta) + lambda_* X  # (m*n)dot(n*p)\n",
        "    Theta_grad = np.dot(Z2.T,X) + lambda_* Theta # (m*n)dot(m*p)\n",
        "        \n",
        "    J +=  0.5*lambda_*(np.sum(np.square(X))+np.sum(np.square(Theta)))\n",
        "    # =============================================================\n",
        "    \n",
        "    grad = np.concatenate([X_grad.ravel(), Theta_grad.ravel()])\n",
        "    return J, grad"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YuoFg3rxrO_g",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def trainRecommender(Y, R, X, Theta, n_users, features, reg, option, verbose=1):\n",
        "    \n",
        "    Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "    res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                                   num_movies, features, reg),\n",
        "                            initial_parameters,\n",
        "                            method='TNC',\n",
        "                            jac=True,\n",
        "                            options=option)\n",
        "    theta = res.x\n",
        "\n",
        "    # Unfold the returned theta back into U and W\n",
        "    X = theta[:num_movies*features].reshape(num_movies, features)\n",
        "    Theta = theta[num_movies*features:].reshape(num_users, features)\n",
        "\n",
        "    if verbose:\n",
        "        print('Recommender system learning completed.')\n",
        "    \n",
        "    return (X, Theta, Ynorm, Ymean)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ZYxx2697Vpbs",
        "colab": {}
      },
      "source": [
        "def normalizeRatings(Y, R):\n",
        "    \"\"\"\n",
        "    Preprocess data by subtracting mean rating for every movie (every row).\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    Y : array_like\n",
        "        The user ratings for all movies. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    R : array_like\n",
        "        Indicator matrix for movies rated by users. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    Ynorm : array_like\n",
        "        A matrix of same shape as Y, after mean normalization.\n",
        "\n",
        "    Ymean : array_like\n",
        "        A vector of shape (num_movies, ) containing the mean rating for each movie.\n",
        "    \"\"\"\n",
        "    m, n = Y.shape\n",
        "    Ymean = np.zeros(m)\n",
        "    Ynorm = np.zeros(Y.shape)\n",
        "\n",
        "    for i in range(m):\n",
        "        idx = R[i, :] == 1\n",
        "        Ymean[i] = np.mean(Y[i, idx])\n",
        "        Ynorm[i, idx] = Y[i, idx] - Ymean[i]\n",
        "\n",
        "    return Ynorm, Ymean\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-_IlHWROZQBj",
        "colab_type": "code",
        "outputId": "c56e9659-d493-4161-99f8-cfb0ee196de0",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 33
        }
      },
      "source": [
        "pd.DataFrame(predictions).shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(514, 471)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 87
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FiXDCYP-vkjw",
        "colab_type": "code",
        "outputId": "524fbcd5-9a50-46a1-abed-9482e939aef6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "#Lazy Grid Search - looping over all the options\n",
        "\n",
        "results = []\n",
        "rnd = 0\n",
        "\n",
        "for ftrs in num_features:\n",
        "    for regu in lambda_:\n",
        "        for option in options:\n",
        "            \n",
        "            #  X : (num_movies  x num_features) matrix of movie features >>>   X = (1682 X p)\n",
        "            #  Theta : (num_users  x num_features) matrix of user features >>> Theta = (943 X p)\n",
        "\n",
        "            # Set Initial Parameters (Theta, X)\n",
        "            X = np.random.randn(num_movies, ftrs)\n",
        "            Theta = np.random.randn(num_users, ftrs)\n",
        "\n",
        "            initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n",
        "            \n",
        "            X, Theta, Ynorm, Ymean = trainRecommender(Y, R, X, Theta, num_users, ftrs, regu, option)\n",
        "            \n",
        "            #Predictions:\n",
        "            p = np.dot(X, Theta.T)\n",
        "\n",
        "            #Adding back the mean of every movie, Ymean\n",
        "            predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "            train_predictions = pd.DataFrame(predictions)\n",
        "            train_predictions.columns = list(range(1,num_users+1))\n",
        "            \n",
        "            '''\n",
        "            The best way I've found to do this..\n",
        "            Looping over the test pivot and locating the corresponding cell in the train set,\n",
        "            by INDEX, where the test-pivot has a rating.\n",
        "            '''\n",
        "            true_val = []\n",
        "            validation_val = []\n",
        "            for i, row in pivot_test.iterrows():\n",
        "                idx = i\n",
        "                for j, cell in enumerate(row):\n",
        "                    jdx = j\n",
        "                    if cell!=0 and (pivot_test.columns[j] in pivot_train.columns):\n",
        "                        validation_val.append(train_predictions.iloc[i,j])\n",
        "                        true_val.append(cell)\n",
        "                        \n",
        "            true_val = np.array(true_val)\n",
        "            validation_val = np.array(validation_val)\n",
        "            MSE = np.round(np.square(true_val - validation_val).mean(),4)\n",
        "            MAE = np.round(np.abs(true_val - validation_val).mean(),4)\n",
        "            \n",
        "            print('MSE: {}, MAE: {}'.format(MSE, MAE))\n",
        "            print(\"number of features: {}, iter: {}, lambda: {}\".format(ftrs, option, regu))\n",
        "            \n",
        "            results.append([MSE, MAE, ftrs, option, regu])\n",
        "            rnd+=1"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Recommender system learning completed.\n",
            "MSE: 1.476, MAE: 0.9727\n",
            "number of features: 5, iter: {'maxiter': 50}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4469, MAE: 0.959\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4529, MAE: 0.9595\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4492, MAE: 0.9592\n",
            "number of features: 5, iter: {'maxiter': 200}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4501, MAE: 0.9592\n",
            "number of features: 5, iter: {'maxiter': 300}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4502, MAE: 0.9594\n",
            "number of features: 5, iter: {'maxiter': 400}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4493, MAE: 0.9649\n",
            "number of features: 5, iter: {'maxiter': 50}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4313, MAE: 0.9578\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4317, MAE: 0.9577\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4317, MAE: 0.9577\n",
            "number of features: 5, iter: {'maxiter': 200}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4317, MAE: 0.9577\n",
            "number of features: 5, iter: {'maxiter': 300}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4317, MAE: 0.9577\n",
            "number of features: 5, iter: {'maxiter': 400}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4829, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 50}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 200}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 300}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 5, iter: {'maxiter': 400}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 50}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 200}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 300}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 5, iter: {'maxiter': 400}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.5217, MAE: 0.987\n",
            "number of features: 10, iter: {'maxiter': 50}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4599, MAE: 0.9629\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4672, MAE: 0.9658\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4604, MAE: 0.9639\n",
            "number of features: 10, iter: {'maxiter': 200}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4613, MAE: 0.9639\n",
            "number of features: 10, iter: {'maxiter': 300}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4584, MAE: 0.9632\n",
            "number of features: 10, iter: {'maxiter': 400}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4306, MAE: 0.9576\n",
            "number of features: 10, iter: {'maxiter': 50}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4325, MAE: 0.958\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4323, MAE: 0.9582\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4323, MAE: 0.9582\n",
            "number of features: 10, iter: {'maxiter': 200}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4318, MAE: 0.958\n",
            "number of features: 10, iter: {'maxiter': 300}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4318, MAE: 0.958\n",
            "number of features: 10, iter: {'maxiter': 400}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.484, MAE: 0.9778\n",
            "number of features: 10, iter: {'maxiter': 50}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 10, iter: {'maxiter': 200}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 10, iter: {'maxiter': 300}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4828, MAE: 0.9775\n",
            "number of features: 10, iter: {'maxiter': 400}, lambda: 50\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 50}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 200}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 300}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.495, MAE: 0.9816\n",
            "number of features: 10, iter: {'maxiter': 400}, lambda: 100\n",
            "Recommender system learning completed.\n",
            "MSE: 1.5614, MAE: 0.9968\n",
            "number of features: 15, iter: {'maxiter': 50}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4656, MAE: 0.9655\n",
            "number of features: 15, iter: {'maxiter': 100}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4754, MAE: 0.968\n",
            "number of features: 15, iter: {'maxiter': 150}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4727, MAE: 0.9677\n",
            "number of features: 15, iter: {'maxiter': 200}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4671, MAE: 0.9661\n",
            "number of features: 15, iter: {'maxiter': 300}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4682, MAE: 0.9664\n",
            "number of features: 15, iter: {'maxiter': 400}, lambda: 10\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4642, MAE: 0.9699\n",
            "number of features: 15, iter: {'maxiter': 50}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4343, MAE: 0.9589\n",
            "number of features: 15, iter: {'maxiter': 100}, lambda: 20\n",
            "Recommender system learning completed.\n",
            "MSE: 1.4322, MAE: 0.9582\n",
            "number of features: 15, iter: {'maxiter': 150}, lambda: 20\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "fqNvC02unyz5",
        "colab_type": "code",
        "outputId": "3be8984d-ed64-4d1e-a3ca-b934e98f7be1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "results = pd.DataFrame(results)\n",
        "results.columns = ['RMSE', 'MAE', 'NumOfFeatures', 'Iter', 'Lambda']\n",
        "results.RMSE = np.sqrt(results.RMSE)\n",
        "\n",
        "print(\"Grid search results:\")\n",
        "results.sort_values(by='MAE')"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Grid search results:\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>RMSE</th>\n",
              "      <th>MAE</th>\n",
              "      <th>NumOfFeatures</th>\n",
              "      <th>Iter</th>\n",
              "      <th>Lambda</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>1.011189</td>\n",
              "      <td>0.9566</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1.011583</td>\n",
              "      <td>0.9569</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>79</th>\n",
              "      <td>1.011255</td>\n",
              "      <td>0.9575</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>11</th>\n",
              "      <td>1.011278</td>\n",
              "      <td>0.9577</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10</th>\n",
              "      <td>1.011278</td>\n",
              "      <td>0.9577</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>1.011278</td>\n",
              "      <td>0.9577</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>30</th>\n",
              "      <td>1.011264</td>\n",
              "      <td>0.9577</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>1.011280</td>\n",
              "      <td>0.9578</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>103</th>\n",
              "      <td>1.011278</td>\n",
              "      <td>0.9579</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>34</th>\n",
              "      <td>1.011280</td>\n",
              "      <td>0.9580</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>35</th>\n",
              "      <td>1.011280</td>\n",
              "      <td>0.9580</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>55</th>\n",
              "      <td>1.011295</td>\n",
              "      <td>0.9581</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>83</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>33</th>\n",
              "      <td>1.011293</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>56</th>\n",
              "      <td>1.011286</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>57</th>\n",
              "      <td>1.011286</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>107</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>80</th>\n",
              "      <td>1.011286</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>81</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>31</th>\n",
              "      <td>1.011300</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>106</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>105</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>104</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>58</th>\n",
              "      <td>1.011284</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>82</th>\n",
              "      <td>1.011289</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>59</th>\n",
              "      <td>1.011284</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>1.011302</td>\n",
              "      <td>0.9582</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>32</th>\n",
              "      <td>1.011295</td>\n",
              "      <td>0.9584</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>1.011681</td>\n",
              "      <td>0.9593</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>1.011688</td>\n",
              "      <td>0.9593</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>...</th>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>117</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>93</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>119</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>91</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>42</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>43</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>44</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>45</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>46</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>47</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>10</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>92</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>19</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>21</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>18</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>66</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>67</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>68</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>69</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 200}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>70</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>23</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>71</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 400}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>90</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>118</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>22</th>\n",
              "      <td>1.012646</td>\n",
              "      <td>0.9816</td>\n",
              "      <td>5</td>\n",
              "      <td>{'maxiter': 300}</td>\n",
              "      <td>100</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>102</th>\n",
              "      <td>1.012728</td>\n",
              "      <td>0.9829</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>20</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>108</th>\n",
              "      <td>1.013012</td>\n",
              "      <td>0.9869</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>50</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>48</th>\n",
              "      <td>1.013108</td>\n",
              "      <td>0.9875</td>\n",
              "      <td>15</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>72</th>\n",
              "      <td>1.015157</td>\n",
              "      <td>1.0167</td>\n",
              "      <td>30</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>96</th>\n",
              "      <td>1.018052</td>\n",
              "      <td>1.0612</td>\n",
              "      <td>50</td>\n",
              "      <td>{'maxiter': 50}</td>\n",
              "      <td>10</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>120 rows × 5 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "         RMSE     MAE  NumOfFeatures              Iter  Lambda\n",
              "6    1.011189  0.9566              5   {'maxiter': 50}      20\n",
              "0    1.011583  0.9569              5   {'maxiter': 50}      10\n",
              "79   1.011255  0.9575             30  {'maxiter': 100}      20\n",
              "11   1.011278  0.9577              5  {'maxiter': 400}      20\n",
              "10   1.011278  0.9577              5  {'maxiter': 300}      20\n",
              "9    1.011278  0.9577              5  {'maxiter': 200}      20\n",
              "30   1.011264  0.9577             10   {'maxiter': 50}      20\n",
              "8    1.011280  0.9578              5  {'maxiter': 150}      20\n",
              "103  1.011278  0.9579             50  {'maxiter': 100}      20\n",
              "34   1.011280  0.9580             10  {'maxiter': 300}      20\n",
              "35   1.011280  0.9580             10  {'maxiter': 400}      20\n",
              "55   1.011295  0.9581             15  {'maxiter': 100}      20\n",
              "83   1.011289  0.9582             30  {'maxiter': 400}      20\n",
              "33   1.011293  0.9582             10  {'maxiter': 200}      20\n",
              "56   1.011286  0.9582             15  {'maxiter': 150}      20\n",
              "57   1.011286  0.9582             15  {'maxiter': 200}      20\n",
              "107  1.011289  0.9582             50  {'maxiter': 400}      20\n",
              "80   1.011286  0.9582             30  {'maxiter': 150}      20\n",
              "81   1.011289  0.9582             30  {'maxiter': 200}      20\n",
              "31   1.011300  0.9582             10  {'maxiter': 100}      20\n",
              "106  1.011289  0.9582             50  {'maxiter': 300}      20\n",
              "105  1.011289  0.9582             50  {'maxiter': 200}      20\n",
              "104  1.011289  0.9582             50  {'maxiter': 150}      20\n",
              "58   1.011284  0.9582             15  {'maxiter': 300}      20\n",
              "82   1.011289  0.9582             30  {'maxiter': 300}      20\n",
              "59   1.011284  0.9582             15  {'maxiter': 400}      20\n",
              "7    1.011302  0.9582              5  {'maxiter': 100}      20\n",
              "32   1.011295  0.9584             10  {'maxiter': 150}      20\n",
              "4    1.011681  0.9593              5  {'maxiter': 300}      10\n",
              "3    1.011688  0.9593              5  {'maxiter': 200}      10\n",
              "..        ...     ...            ...               ...     ...\n",
              "117  1.012646  0.9816             50  {'maxiter': 200}     100\n",
              "93   1.012646  0.9816             30  {'maxiter': 200}     100\n",
              "119  1.012646  0.9816             50  {'maxiter': 400}     100\n",
              "91   1.012646  0.9816             30  {'maxiter': 100}     100\n",
              "20   1.012646  0.9816              5  {'maxiter': 150}     100\n",
              "42   1.012646  0.9816             10   {'maxiter': 50}     100\n",
              "43   1.012646  0.9816             10  {'maxiter': 100}     100\n",
              "44   1.012646  0.9816             10  {'maxiter': 150}     100\n",
              "45   1.012646  0.9816             10  {'maxiter': 200}     100\n",
              "46   1.012646  0.9816             10  {'maxiter': 300}     100\n",
              "47   1.012646  0.9816             10  {'maxiter': 400}     100\n",
              "92   1.012646  0.9816             30  {'maxiter': 150}     100\n",
              "19   1.012646  0.9816              5  {'maxiter': 100}     100\n",
              "21   1.012646  0.9816              5  {'maxiter': 200}     100\n",
              "18   1.012646  0.9816              5   {'maxiter': 50}     100\n",
              "66   1.012646  0.9816             15   {'maxiter': 50}     100\n",
              "67   1.012646  0.9816             15  {'maxiter': 100}     100\n",
              "68   1.012646  0.9816             15  {'maxiter': 150}     100\n",
              "69   1.012646  0.9816             15  {'maxiter': 200}     100\n",
              "70   1.012646  0.9816             15  {'maxiter': 300}     100\n",
              "23   1.012646  0.9816              5  {'maxiter': 400}     100\n",
              "71   1.012646  0.9816             15  {'maxiter': 400}     100\n",
              "90   1.012646  0.9816             30   {'maxiter': 50}     100\n",
              "118  1.012646  0.9816             50  {'maxiter': 300}     100\n",
              "22   1.012646  0.9816              5  {'maxiter': 300}     100\n",
              "102  1.012728  0.9829             50   {'maxiter': 50}      20\n",
              "108  1.013012  0.9869             50   {'maxiter': 50}      50\n",
              "48   1.013108  0.9875             15   {'maxiter': 50}      10\n",
              "72   1.015157  1.0167             30   {'maxiter': 50}      10\n",
              "96   1.018052  1.0612             50   {'maxiter': 50}      10\n",
              "\n",
              "[120 rows x 5 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 87
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kbW3AkTRxKfO",
        "colab_type": "text"
      },
      "source": [
        "#Movie-lens 2018 (Sparse MF)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZdpQw7tNxB23",
        "colab_type": "text"
      },
      "source": [
        "## Data"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tascdmX9xt-B",
        "colab_type": "code",
        "outputId": "a37fb30a-0bf2-4392-e7ef-49256a165ee6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 33
        }
      },
      "source": [
        "#Some Imports \n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import collections\n",
        "import seaborn as sns\n",
        "%matplotlib inline\n",
        "from IPython import display\n",
        "from matplotlib import pyplot as plt\n",
        "import sklearn\n",
        "import sklearn.manifold\n",
        "\n",
        "#Get the Data\n",
        "#NEW MOVIELENS - download the NEW MovieLens Data, and create DataFrames containing movies, users, and ratings.\n",
        "\n",
        "print(\"Downloading movielens data...\")\n",
        "import zipfile\n",
        "import urllib.request\n",
        "\n",
        "    \n",
        "urllib.request.urlretrieve(\"http://files.grouplens.org/datasets/movielens/ml-latest-small.zip\", \"movielens.zip\")\n",
        "\n",
        "zip_ref = zipfile.ZipFile('movielens.zip', \"r\")\n",
        "zip_ref.extractall()\n",
        "\n",
        "ratings_cols = ['user_id', 'movie_id', 'rating', 'unix_timestamp']\n",
        "ratings = pd.read_csv('ml-latest-small/ratings.csv', names=ratings_cols, sep=',', encoding='latin-1', header = None)\n",
        "ratings.drop([0], inplace=True)\n",
        "ratings.drop('unix_timestamp', axis =1, inplace=True)\n",
        "\n",
        "movies_cols = ['movie_id', 'title', 'genres']\n",
        "movies = pd.read_csv('ml-latest-small/movies.csv',names=movies_cols, sep=',', encoding='latin-1')\n",
        "movies.drop([0], inplace=True)\n",
        "movies.drop('genres', axis = 1, inplace = True)\n",
        "\n",
        "# Create one merged DataFrame containing all the movielens data.\n",
        "movielens = ratings.merge(movies, on='movie_id')\n",
        "movielens.rating = movielens.rating.astype(float)\n",
        "movielens.user_id = movielens.user_id.astype(int)\n",
        "movielens.movie_id = movielens.movie_id.astype(int)\n",
        "\n",
        "# Utility to split the data into training and test sets.\n",
        "def split_dataframe(df, holdout_fraction=0.1):\n",
        "    \"\"\"Splits a DataFrame into training and test sets.\n",
        "    Args:\n",
        "    df: a dataframe.\n",
        "    holdout_fraction: fraction of dataframe rows to use in the test set.\n",
        "    Returns:\n",
        "    train: dataframe for training\n",
        "    test: dataframe for testing\n",
        "    \"\"\"\n",
        "    test = df.sample(frac=holdout_fraction, replace=False)\n",
        "    train = df[~df.index.isin(test.index)]\n",
        "    return train, test\n",
        "\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Downloading movielens data...\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "zqAbygl2KSdO",
        "colab_type": "code",
        "outputId": "c8a9b45f-4e4b-4d82-9203-fa22259f324c",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "# D O   N O T   R U N ! ! ! \n",
        "\n",
        "# Ver1 -  Create a Random Data for Baseline\n",
        "import random\n",
        "movielens['rating'] = np.random.randint(1, 6, movielens.shape[0])\n",
        "movielens.rating = movielens.rating.astype(float)\n",
        "movielens.head(30)\n",
        "\n",
        "# Ver2 -  Create a Normalize Distributed Random Data for Baseline\n",
        "import scipy.stats as ss\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "x = np.arange(-2, 3)\n",
        "xU, xL = x + 0.5, x - 0.5 \n",
        "prob = ss.norm.cdf(xU, scale = 1) - ss.norm.cdf(xL, scale = 1)\n",
        "prob = prob / prob.sum() #normalize the probabilities so their sum is 1\n",
        "nums = np.random.choice(x, size =movielens.shape[0], p = prob)\n",
        "nums = nums + 3\n",
        "\n",
        "movielens['rating'] = nums\n",
        "movielens.rating = movielens.rating.astype(float)\n",
        "movielens.head()\n",
        "\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "      <th>title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>3.0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>5</td>\n",
              "      <td>1</td>\n",
              "      <td>2.0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>7</td>\n",
              "      <td>1</td>\n",
              "      <td>3.0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>15</td>\n",
              "      <td>1</td>\n",
              "      <td>3.0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>17</td>\n",
              "      <td>1</td>\n",
              "      <td>4.0</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   user_id  movie_id  rating             title\n",
              "0        1         1     3.0  Toy Story (1995)\n",
              "1        5         1     2.0  Toy Story (1995)\n",
              "2        7         1     3.0  Toy Story (1995)\n",
              "3       15         1     3.0  Toy Story (1995)\n",
              "4       17         1     4.0  Toy Story (1995)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 94
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NlyBl-d00vbS",
        "colab_type": "text"
      },
      "source": [
        "## Model"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-dZe-P6uyJ_A",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "pivot = movielens.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot.fillna(0, inplace = True)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2h78yrJCyUnw",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def cofiCostFunc(params, Y, R, num_users, num_movies,\n",
        "                      num_features, lambda_=0.0):\n",
        "    \"\"\"\n",
        "    Collaborative filtering cost function.\n",
        "    \n",
        "    Parameters\n",
        "    ----------\n",
        "    params : array_like\n",
        "        The parameters which will be optimized. This is a one\n",
        "        dimensional vector of shape (num_movies x num_users, 1). It is the \n",
        "        concatenation of the feature vectors X and parameters Theta.\n",
        "    \n",
        "    Y : array_like\n",
        "        A matrix of shape (num_movies x num_users) of user ratings of movies.\n",
        "    \n",
        "    R : array_like\n",
        "        A (num_movies x num_users) matrix, where R[i, j] = 1 if the \n",
        "        i-th movie was rated by the j-th user.\n",
        "    \n",
        "    num_users : int\n",
        "        Total number of users.\n",
        "    \n",
        "    num_movies : int\n",
        "        Total number of movies.\n",
        "    \n",
        "    num_features : int\n",
        "        Number of features to learn.\n",
        "    \n",
        "    lambda_ : float, optional\n",
        "        The regularization coefficient.\n",
        "    \n",
        "    Returns\n",
        "    -------\n",
        "    J : float\n",
        "        The value of the cost function at the given params.\n",
        "    \n",
        "    grad : array_like\n",
        "        The gradient vector of the cost function at the given params.\n",
        "        grad has a shape (num_movies x num_users, 1)\n",
        "    \n",
        "    Instructions\n",
        "    ------------\n",
        "    Compute the cost function and gradient for collaborative filtering.\n",
        "    Concretely, you should first implement the cost function (without\n",
        "    regularization) and make sure it is matches our costs. After that,\n",
        "    you should implement thegradient and use the checkCostFunction routine \n",
        "    to check that the gradient is correct. Finally, you should implement\n",
        "    regularization.\n",
        "    \n",
        "    Notes\n",
        "    -----\n",
        "    - The input params will be unraveled into the two matrices:\n",
        "        X : (num_movies  x num_features) matrix of movie features >>>   X (m * p)\n",
        "        Theta : (num_users  x num_features) matrix of user features >>> Theta (n * p)\n",
        "\n",
        "    - You should set the following variables correctly:\n",
        "\n",
        "        X_grad : (num_movies x num_features) matrix, containing the \n",
        "                 partial derivatives w.r.t. to each element of X\n",
        "        Theta_grad : (num_users x num_features) matrix, containing the \n",
        "                     partial derivatives w.r.t. to each element of Theta\n",
        "\n",
        "    - The returned gradient will be the concatenation of the raveled \n",
        "      gradients X_grad and Theta_grad.\n",
        "    \"\"\"\n",
        "    # Unfold the X and Theta matrices from params\n",
        "    X = params[:num_movies*num_features].reshape(num_movies, num_features) # (m * p)\n",
        "    Theta = params[num_movies*num_features:].reshape(num_users, num_features) # (n * p)\n",
        "\n",
        "    # You need to return the following values correctly\n",
        "    J = 0\n",
        "    X_grad = np.zeros(X.shape)\n",
        "    Theta_grad = np.zeros(Theta.shape)\n",
        "\n",
        "    # ====================== YOUR CODE HERE ======================\n",
        "\n",
        "    M = np.dot(X, Theta.T)\n",
        "    Z = np.square(np.multiply(R , M) - Y) # (m * n) \n",
        "    J = 0.5 * np.sum(Z)\n",
        "    \n",
        "    Z2 = np.multiply(R , M) - Y #(m * n) \n",
        "\n",
        "    X_grad = np.dot(Z2,Theta) + lambda_* X  # (m*n)dot(n*p)\n",
        "    Theta_grad = np.dot(Z2.T,X) + lambda_* Theta # (m*n)dot(m*p)\n",
        "        \n",
        "    J +=  0.5*lambda_*(np.sum(np.square(X))+np.sum(np.square(Theta)))\n",
        "    # =============================================================\n",
        "    \n",
        "    grad = np.concatenate([X_grad.ravel(), Theta_grad.ravel()])\n",
        "    return J, grad"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5xEFYg7qydCA",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def normalizeRatings(Y, R):\n",
        "    \"\"\"\n",
        "    Preprocess data by subtracting mean rating for every movie (every row).\n",
        "\n",
        "    Parameters\n",
        "    ----------\n",
        "    Y : array_like\n",
        "        The user ratings for all movies. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    R : array_like\n",
        "        Indicator matrix for movies rated by users. A matrix of shape (num_movies x num_users).\n",
        "\n",
        "    Returns\n",
        "    -------\n",
        "    Ynorm : array_like\n",
        "        A matrix of same shape as Y, after mean normalization.\n",
        "\n",
        "    Ymean : array_like\n",
        "        A vector of shape (num_movies, ) containing the mean rating for each movie.\n",
        "    \"\"\"\n",
        "    m, n = Y.shape\n",
        "    Ymean = np.zeros(m)\n",
        "    Ynorm = np.zeros(Y.shape)\n",
        "\n",
        "    for i in range(m):\n",
        "        idx = R[i, :] == 1\n",
        "        Ymean[i] = np.mean(Y[i, idx])\n",
        "        Ynorm[i, idx] = Y[i, idx] - Ymean[i]\n",
        "\n",
        "    return Ynorm, Ymean\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FF-U8XvEydFJ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#  Useful Values\n",
        "num_movies, num_users = pivot.shape\n",
        "num_features = 10\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0TPiS6klydI0",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by \n",
        "#  943 users\n",
        "\n",
        "Y = pivot.values\n",
        "\n",
        "#  R is a 1682x943 matrix, where R(i,j) = 1 if and only if user j gave a\n",
        "#  rating to movie i\n",
        "\n",
        "idx = np.where(pivot>0)\n",
        "\n",
        "R = np.zeros_like(Y)\n",
        "\n",
        "R[idx] = 1\n",
        "\n",
        "#  X : (num_movies  x num_features) matrix of movie features >>>   X = (1682 X p)\n",
        "#  Theta : (num_users  x num_features) matrix of user features >>> Theta = (943 X p)\n",
        "\n",
        "# Set Initial Parameters (Theta, X)\n",
        "X = np.random.randn(num_movies, num_features)\n",
        "Theta = np.random.randn(num_users, num_features)\n",
        "\n",
        "initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "rwBgdZSpyVq1",
        "outputId": "22319237-9369-437d-e7d3-a402e443053f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "from scipy import optimize\n",
        "\n",
        "def trainRecommender(Y, R, X, Theta, n_users = 943):\n",
        "    \n",
        "    Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "    # Set options for scipy.optimize.minimize\n",
        "    options = {'maxiter': 100}\n",
        "\n",
        "    # Set Regularization\n",
        "    lambda_ = 10\n",
        "    res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                                   num_movies, num_features, lambda_),\n",
        "                            initial_parameters,\n",
        "                            method='TNC',\n",
        "                            jac=True,\n",
        "                            options=options)\n",
        "    theta = res.x\n",
        "\n",
        "    # Unfold the returned theta back into U and W\n",
        "    X = theta[:num_movies*num_features].reshape(num_movies, num_features)\n",
        "    Theta = theta[num_movies*num_features:].reshape(num_users, num_features)\n",
        "\n",
        "    print('Recommender system learning completed.')\n",
        "    \n",
        "    return (X, Theta, Ynorm, Ymean)\n",
        "    \n",
        "X, Theta, Ynorm, Ymean = trainRecommender(Y, R, X, Theta)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Recommender system learning completed.\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "NUCCjrtyyVq9",
        "outputId": "ff7432e2-13fc-41c5-9844-8a231192759f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 244
        }
      },
      "source": [
        "#Predictions:\n",
        "p = np.dot(X, Theta.T)\n",
        "\n",
        "#Adding back the mean of every movie, Ymean\n",
        "predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "pd.DataFrame(predictions).head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>0</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>3</th>\n",
              "      <th>4</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>8</th>\n",
              "      <th>9</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>12</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>17</th>\n",
              "      <th>18</th>\n",
              "      <th>19</th>\n",
              "      <th>20</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>26</th>\n",
              "      <th>27</th>\n",
              "      <th>28</th>\n",
              "      <th>29</th>\n",
              "      <th>30</th>\n",
              "      <th>31</th>\n",
              "      <th>32</th>\n",
              "      <th>33</th>\n",
              "      <th>34</th>\n",
              "      <th>35</th>\n",
              "      <th>36</th>\n",
              "      <th>37</th>\n",
              "      <th>38</th>\n",
              "      <th>39</th>\n",
              "      <th>...</th>\n",
              "      <th>570</th>\n",
              "      <th>571</th>\n",
              "      <th>572</th>\n",
              "      <th>573</th>\n",
              "      <th>574</th>\n",
              "      <th>575</th>\n",
              "      <th>576</th>\n",
              "      <th>577</th>\n",
              "      <th>578</th>\n",
              "      <th>579</th>\n",
              "      <th>580</th>\n",
              "      <th>581</th>\n",
              "      <th>582</th>\n",
              "      <th>583</th>\n",
              "      <th>584</th>\n",
              "      <th>585</th>\n",
              "      <th>586</th>\n",
              "      <th>587</th>\n",
              "      <th>588</th>\n",
              "      <th>589</th>\n",
              "      <th>590</th>\n",
              "      <th>591</th>\n",
              "      <th>592</th>\n",
              "      <th>593</th>\n",
              "      <th>594</th>\n",
              "      <th>595</th>\n",
              "      <th>596</th>\n",
              "      <th>597</th>\n",
              "      <th>598</th>\n",
              "      <th>599</th>\n",
              "      <th>600</th>\n",
              "      <th>601</th>\n",
              "      <th>602</th>\n",
              "      <th>603</th>\n",
              "      <th>604</th>\n",
              "      <th>605</th>\n",
              "      <th>606</th>\n",
              "      <th>607</th>\n",
              "      <th>608</th>\n",
              "      <th>609</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>2.958274</td>\n",
              "      <td>2.928583</td>\n",
              "      <td>2.969944</td>\n",
              "      <td>2.759122</td>\n",
              "      <td>2.914388</td>\n",
              "      <td>3.243831</td>\n",
              "      <td>2.989084</td>\n",
              "      <td>3.018421</td>\n",
              "      <td>2.996292</td>\n",
              "      <td>2.985064</td>\n",
              "      <td>3.004707</td>\n",
              "      <td>2.927244</td>\n",
              "      <td>3.012386</td>\n",
              "      <td>3.027360</td>\n",
              "      <td>3.099424</td>\n",
              "      <td>2.888253</td>\n",
              "      <td>2.914051</td>\n",
              "      <td>2.469945</td>\n",
              "      <td>2.588055</td>\n",
              "      <td>3.294047</td>\n",
              "      <td>2.737194</td>\n",
              "      <td>2.961968</td>\n",
              "      <td>2.936112</td>\n",
              "      <td>2.982273</td>\n",
              "      <td>2.907497</td>\n",
              "      <td>2.987538</td>\n",
              "      <td>2.763446</td>\n",
              "      <td>3.318889</td>\n",
              "      <td>2.825625</td>\n",
              "      <td>2.924302</td>\n",
              "      <td>3.136568</td>\n",
              "      <td>3.057916</td>\n",
              "      <td>3.070731</td>\n",
              "      <td>2.966223</td>\n",
              "      <td>3.005684</td>\n",
              "      <td>2.952484</td>\n",
              "      <td>3.030594</td>\n",
              "      <td>3.045444</td>\n",
              "      <td>2.972203</td>\n",
              "      <td>3.021322</td>\n",
              "      <td>...</td>\n",
              "      <td>3.079850</td>\n",
              "      <td>3.053088</td>\n",
              "      <td>3.137889</td>\n",
              "      <td>3.027112</td>\n",
              "      <td>3.059172</td>\n",
              "      <td>2.980965</td>\n",
              "      <td>3.040445</td>\n",
              "      <td>2.954340</td>\n",
              "      <td>3.048658</td>\n",
              "      <td>2.781427</td>\n",
              "      <td>3.007271</td>\n",
              "      <td>3.023303</td>\n",
              "      <td>3.002793</td>\n",
              "      <td>2.982634</td>\n",
              "      <td>2.968817</td>\n",
              "      <td>2.958905</td>\n",
              "      <td>2.888724</td>\n",
              "      <td>2.978270</td>\n",
              "      <td>2.973623</td>\n",
              "      <td>3.103582</td>\n",
              "      <td>3.027413</td>\n",
              "      <td>3.059414</td>\n",
              "      <td>2.895860</td>\n",
              "      <td>2.841157</td>\n",
              "      <td>2.998016</td>\n",
              "      <td>2.670832</td>\n",
              "      <td>2.449227</td>\n",
              "      <td>3.020320</td>\n",
              "      <td>2.983533</td>\n",
              "      <td>2.863295</td>\n",
              "      <td>2.896243</td>\n",
              "      <td>3.125505</td>\n",
              "      <td>3.041039</td>\n",
              "      <td>2.890254</td>\n",
              "      <td>2.902862</td>\n",
              "      <td>2.529774</td>\n",
              "      <td>2.910720</td>\n",
              "      <td>3.535207</td>\n",
              "      <td>2.743749</td>\n",
              "      <td>3.543847</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>3.265990</td>\n",
              "      <td>3.090658</td>\n",
              "      <td>3.012521</td>\n",
              "      <td>3.165260</td>\n",
              "      <td>3.108188</td>\n",
              "      <td>2.971156</td>\n",
              "      <td>3.027011</td>\n",
              "      <td>2.961964</td>\n",
              "      <td>3.032041</td>\n",
              "      <td>2.927301</td>\n",
              "      <td>2.964025</td>\n",
              "      <td>3.035953</td>\n",
              "      <td>3.014228</td>\n",
              "      <td>2.975819</td>\n",
              "      <td>2.894330</td>\n",
              "      <td>3.194470</td>\n",
              "      <td>3.121495</td>\n",
              "      <td>3.181110</td>\n",
              "      <td>3.552308</td>\n",
              "      <td>2.695677</td>\n",
              "      <td>3.277391</td>\n",
              "      <td>2.977269</td>\n",
              "      <td>3.053486</td>\n",
              "      <td>3.070671</td>\n",
              "      <td>3.132493</td>\n",
              "      <td>3.016257</td>\n",
              "      <td>3.108185</td>\n",
              "      <td>3.243772</td>\n",
              "      <td>3.231181</td>\n",
              "      <td>3.071450</td>\n",
              "      <td>2.871448</td>\n",
              "      <td>3.070474</td>\n",
              "      <td>2.926522</td>\n",
              "      <td>3.053711</td>\n",
              "      <td>3.017166</td>\n",
              "      <td>3.074766</td>\n",
              "      <td>2.945123</td>\n",
              "      <td>2.923615</td>\n",
              "      <td>3.145454</td>\n",
              "      <td>3.017744</td>\n",
              "      <td>...</td>\n",
              "      <td>2.946406</td>\n",
              "      <td>2.894268</td>\n",
              "      <td>2.852022</td>\n",
              "      <td>2.968041</td>\n",
              "      <td>2.937567</td>\n",
              "      <td>3.032654</td>\n",
              "      <td>2.887015</td>\n",
              "      <td>2.985075</td>\n",
              "      <td>3.046266</td>\n",
              "      <td>3.137094</td>\n",
              "      <td>2.929301</td>\n",
              "      <td>3.031604</td>\n",
              "      <td>2.948728</td>\n",
              "      <td>3.126917</td>\n",
              "      <td>3.052873</td>\n",
              "      <td>3.049990</td>\n",
              "      <td>3.052595</td>\n",
              "      <td>3.017026</td>\n",
              "      <td>2.980530</td>\n",
              "      <td>2.432131</td>\n",
              "      <td>3.007165</td>\n",
              "      <td>2.933696</td>\n",
              "      <td>3.137716</td>\n",
              "      <td>3.260346</td>\n",
              "      <td>3.030302</td>\n",
              "      <td>3.205708</td>\n",
              "      <td>3.437206</td>\n",
              "      <td>3.030977</td>\n",
              "      <td>2.448707</td>\n",
              "      <td>3.464847</td>\n",
              "      <td>2.794347</td>\n",
              "      <td>2.935511</td>\n",
              "      <td>2.605961</td>\n",
              "      <td>3.192274</td>\n",
              "      <td>2.880761</td>\n",
              "      <td>3.039412</td>\n",
              "      <td>3.034195</td>\n",
              "      <td>2.855672</td>\n",
              "      <td>3.150425</td>\n",
              "      <td>3.016795</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>2.950295</td>\n",
              "      <td>2.946728</td>\n",
              "      <td>2.866347</td>\n",
              "      <td>2.867522</td>\n",
              "      <td>2.863839</td>\n",
              "      <td>2.616584</td>\n",
              "      <td>2.883870</td>\n",
              "      <td>2.891839</td>\n",
              "      <td>2.902164</td>\n",
              "      <td>2.801089</td>\n",
              "      <td>2.880148</td>\n",
              "      <td>2.893678</td>\n",
              "      <td>2.864290</td>\n",
              "      <td>2.877721</td>\n",
              "      <td>2.979846</td>\n",
              "      <td>2.859398</td>\n",
              "      <td>2.975717</td>\n",
              "      <td>2.569124</td>\n",
              "      <td>2.799409</td>\n",
              "      <td>2.843176</td>\n",
              "      <td>2.877139</td>\n",
              "      <td>2.832525</td>\n",
              "      <td>2.845537</td>\n",
              "      <td>2.940574</td>\n",
              "      <td>2.932844</td>\n",
              "      <td>2.863898</td>\n",
              "      <td>2.808200</td>\n",
              "      <td>2.999763</td>\n",
              "      <td>2.805908</td>\n",
              "      <td>2.884278</td>\n",
              "      <td>2.853867</td>\n",
              "      <td>2.873307</td>\n",
              "      <td>2.997147</td>\n",
              "      <td>2.812989</td>\n",
              "      <td>2.864690</td>\n",
              "      <td>2.868481</td>\n",
              "      <td>2.889697</td>\n",
              "      <td>2.865834</td>\n",
              "      <td>2.879126</td>\n",
              "      <td>2.998839</td>\n",
              "      <td>...</td>\n",
              "      <td>2.914047</td>\n",
              "      <td>2.918329</td>\n",
              "      <td>3.028992</td>\n",
              "      <td>2.864910</td>\n",
              "      <td>2.906652</td>\n",
              "      <td>2.913110</td>\n",
              "      <td>2.850506</td>\n",
              "      <td>2.883312</td>\n",
              "      <td>2.883942</td>\n",
              "      <td>2.784624</td>\n",
              "      <td>2.918299</td>\n",
              "      <td>2.811924</td>\n",
              "      <td>2.897036</td>\n",
              "      <td>2.848256</td>\n",
              "      <td>2.924626</td>\n",
              "      <td>2.867835</td>\n",
              "      <td>3.006594</td>\n",
              "      <td>2.976362</td>\n",
              "      <td>2.891191</td>\n",
              "      <td>3.205819</td>\n",
              "      <td>2.917711</td>\n",
              "      <td>2.865410</td>\n",
              "      <td>2.908282</td>\n",
              "      <td>2.829009</td>\n",
              "      <td>2.939906</td>\n",
              "      <td>2.512126</td>\n",
              "      <td>2.649904</td>\n",
              "      <td>2.896212</td>\n",
              "      <td>1.847488</td>\n",
              "      <td>3.204019</td>\n",
              "      <td>2.835147</td>\n",
              "      <td>2.925105</td>\n",
              "      <td>2.559549</td>\n",
              "      <td>2.914552</td>\n",
              "      <td>2.847891</td>\n",
              "      <td>3.009054</td>\n",
              "      <td>2.835767</td>\n",
              "      <td>3.058454</td>\n",
              "      <td>2.835885</td>\n",
              "      <td>3.617078</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>3.612152</td>\n",
              "      <td>3.751570</td>\n",
              "      <td>3.721582</td>\n",
              "      <td>3.785689</td>\n",
              "      <td>3.680112</td>\n",
              "      <td>3.326576</td>\n",
              "      <td>3.820165</td>\n",
              "      <td>3.705848</td>\n",
              "      <td>3.717282</td>\n",
              "      <td>3.672824</td>\n",
              "      <td>3.699788</td>\n",
              "      <td>3.713306</td>\n",
              "      <td>3.707134</td>\n",
              "      <td>3.719103</td>\n",
              "      <td>3.760251</td>\n",
              "      <td>3.692757</td>\n",
              "      <td>3.748942</td>\n",
              "      <td>3.740331</td>\n",
              "      <td>3.893866</td>\n",
              "      <td>3.693510</td>\n",
              "      <td>3.883944</td>\n",
              "      <td>3.740628</td>\n",
              "      <td>3.713699</td>\n",
              "      <td>3.714455</td>\n",
              "      <td>3.704300</td>\n",
              "      <td>3.688262</td>\n",
              "      <td>3.704923</td>\n",
              "      <td>3.619747</td>\n",
              "      <td>3.597270</td>\n",
              "      <td>3.710847</td>\n",
              "      <td>3.770523</td>\n",
              "      <td>3.673645</td>\n",
              "      <td>3.814282</td>\n",
              "      <td>3.730379</td>\n",
              "      <td>3.683297</td>\n",
              "      <td>3.664506</td>\n",
              "      <td>3.747358</td>\n",
              "      <td>3.737461</td>\n",
              "      <td>3.680393</td>\n",
              "      <td>3.753342</td>\n",
              "      <td>...</td>\n",
              "      <td>3.680768</td>\n",
              "      <td>3.749801</td>\n",
              "      <td>3.762210</td>\n",
              "      <td>3.717716</td>\n",
              "      <td>3.729186</td>\n",
              "      <td>3.731028</td>\n",
              "      <td>3.759872</td>\n",
              "      <td>3.718466</td>\n",
              "      <td>3.669765</td>\n",
              "      <td>3.794446</td>\n",
              "      <td>3.714099</td>\n",
              "      <td>3.658448</td>\n",
              "      <td>3.724246</td>\n",
              "      <td>3.694692</td>\n",
              "      <td>3.740848</td>\n",
              "      <td>3.636060</td>\n",
              "      <td>3.780912</td>\n",
              "      <td>3.774915</td>\n",
              "      <td>3.720978</td>\n",
              "      <td>4.029597</td>\n",
              "      <td>3.738380</td>\n",
              "      <td>3.727661</td>\n",
              "      <td>3.728171</td>\n",
              "      <td>3.727416</td>\n",
              "      <td>3.726776</td>\n",
              "      <td>3.619519</td>\n",
              "      <td>3.500379</td>\n",
              "      <td>3.719801</td>\n",
              "      <td>3.768857</td>\n",
              "      <td>3.881189</td>\n",
              "      <td>3.749450</td>\n",
              "      <td>3.747488</td>\n",
              "      <td>3.946372</td>\n",
              "      <td>3.629802</td>\n",
              "      <td>3.706603</td>\n",
              "      <td>3.857026</td>\n",
              "      <td>3.697651</td>\n",
              "      <td>3.133928</td>\n",
              "      <td>3.694498</td>\n",
              "      <td>3.809922</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>2.862067</td>\n",
              "      <td>2.861005</td>\n",
              "      <td>2.859738</td>\n",
              "      <td>2.903150</td>\n",
              "      <td>2.885210</td>\n",
              "      <td>2.761724</td>\n",
              "      <td>3.057220</td>\n",
              "      <td>2.972674</td>\n",
              "      <td>2.923071</td>\n",
              "      <td>2.991972</td>\n",
              "      <td>2.855316</td>\n",
              "      <td>2.918731</td>\n",
              "      <td>2.856376</td>\n",
              "      <td>2.976979</td>\n",
              "      <td>2.896729</td>\n",
              "      <td>2.746894</td>\n",
              "      <td>2.813691</td>\n",
              "      <td>2.598638</td>\n",
              "      <td>2.201322</td>\n",
              "      <td>3.014962</td>\n",
              "      <td>2.554962</td>\n",
              "      <td>2.876993</td>\n",
              "      <td>2.787811</td>\n",
              "      <td>2.820696</td>\n",
              "      <td>2.846701</td>\n",
              "      <td>2.832530</td>\n",
              "      <td>2.878255</td>\n",
              "      <td>2.905108</td>\n",
              "      <td>2.826895</td>\n",
              "      <td>2.810521</td>\n",
              "      <td>2.975810</td>\n",
              "      <td>2.873899</td>\n",
              "      <td>2.905110</td>\n",
              "      <td>2.844691</td>\n",
              "      <td>2.887933</td>\n",
              "      <td>2.778633</td>\n",
              "      <td>2.893278</td>\n",
              "      <td>2.883540</td>\n",
              "      <td>2.897399</td>\n",
              "      <td>2.963371</td>\n",
              "      <td>...</td>\n",
              "      <td>2.818042</td>\n",
              "      <td>2.856873</td>\n",
              "      <td>3.125704</td>\n",
              "      <td>2.869734</td>\n",
              "      <td>2.902973</td>\n",
              "      <td>2.883499</td>\n",
              "      <td>2.954784</td>\n",
              "      <td>2.843867</td>\n",
              "      <td>2.913606</td>\n",
              "      <td>2.956047</td>\n",
              "      <td>2.880848</td>\n",
              "      <td>2.860993</td>\n",
              "      <td>2.910833</td>\n",
              "      <td>2.874276</td>\n",
              "      <td>2.952672</td>\n",
              "      <td>2.955688</td>\n",
              "      <td>2.875515</td>\n",
              "      <td>2.841044</td>\n",
              "      <td>2.873878</td>\n",
              "      <td>3.493998</td>\n",
              "      <td>3.000243</td>\n",
              "      <td>2.948359</td>\n",
              "      <td>2.832412</td>\n",
              "      <td>2.917601</td>\n",
              "      <td>2.889806</td>\n",
              "      <td>2.515935</td>\n",
              "      <td>2.523241</td>\n",
              "      <td>2.909107</td>\n",
              "      <td>4.012375</td>\n",
              "      <td>3.443053</td>\n",
              "      <td>2.917700</td>\n",
              "      <td>2.849723</td>\n",
              "      <td>2.756510</td>\n",
              "      <td>2.765346</td>\n",
              "      <td>2.854814</td>\n",
              "      <td>3.177562</td>\n",
              "      <td>2.899968</td>\n",
              "      <td>2.415859</td>\n",
              "      <td>2.793205</td>\n",
              "      <td>3.474494</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 610 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "        0         1         2    ...       607       608       609\n",
              "0  2.958274  2.928583  2.969944  ...  3.535207  2.743749  3.543847\n",
              "1  3.265990  3.090658  3.012521  ...  2.855672  3.150425  3.016795\n",
              "2  2.950295  2.946728  2.866347  ...  3.058454  2.835885  3.617078\n",
              "3  3.612152  3.751570  3.721582  ...  3.133928  3.694498  3.809922\n",
              "4  2.862067  2.861005  2.859738  ...  2.415859  2.793205  3.474494\n",
              "\n",
              "[5 rows x 610 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 74
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vbBp9pYqy_C8",
        "colab_type": "text"
      },
      "source": [
        "##Train Test Split & Model Evaluation"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "X9nKtGpn2Okw",
        "colab_type": "code",
        "outputId": "22c0e1aa-75ce-4d91-e6bf-0ecf49e5e6a1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "train_df = movielens.sample(frac=0.8, random_state=0)\n",
        "test_df = movielens.drop(train_df.index)\n",
        "train_df.shape, test_df.shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "((80669, 4), (20167, 4))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 75
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "83f74db4-8d9a-4211-c5a6-faffbd6f0b9a",
        "id": "g-CZNYHf1RZf",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "min_user_clicks = 15\n",
        "filter_users = train_df['user_id'].value_counts() > min_user_clicks\n",
        "filter_users = filter_users[filter_users].index.tolist()\n",
        "\n",
        "min_item_clicks = 15\n",
        "filter_items = train_df['movie_id'].value_counts() > min_item_clicks\n",
        "filter_items = filter_items[filter_items].index.tolist()\n",
        "\n",
        "train_filtered = train_df[(train_df['user_id'].isin(filter_users)) & train_df['movie_id'].isin(filter_items)]\n",
        "print('The original data frame shape:\\t{}'.format(train_df.shape))\n",
        "print('The new data frame shape:\\t{}'.format(train_filtered.shape))\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "The original data frame shape:\t(80669, 4)\n",
            "The new data frame shape:\t(54264, 4)\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5gTJgANAuDuK",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#Check that all users appears in both Train & Test\n",
        "\n",
        "train_users_idx = list(train_filtered.user_id.unique())\n",
        "test_df_idx = list(test_df.user_id.unique())\n",
        "iters = list(set(train_users_idx) & set(test_df_idx))\n",
        "\n",
        "\n",
        "train_filtered = train_filtered[train_filtered.user_id.isin(iters)]\n",
        "test_df = test_df[test_df.user_id.isin(iters)]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0csdbcBvxwUh",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#Check that all movies in Test appears in Train\n",
        "\n",
        "train_movies_inx = list(train_filtered.movie_id.unique())\n",
        "test_movies_inx = list(test_df.movie_id.unique())\n",
        "uniques_movies_test = list(np.setdiff1d(test_movies_inx, train_movies_inx))\n",
        "flt_lst = list(np.setdiff1d(test_movies_inx, uniques_movies_test))\n",
        "\n",
        "\n",
        "test_df = test_df[test_df['movie_id'].isin(flt_lst)]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ShQMMmXdt1Xz",
        "colab_type": "code",
        "outputId": "01099795-521c-4b9c-960c-2ef51bd982e4",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "train_users = list(train_filtered.user_id.unique())\n",
        "test_users = list(test_df.user_id.unique())\n",
        "counter=0\n",
        "for user in test_users:\n",
        "    if user not in train_users:\n",
        "        counter =+ 1\n",
        "print(\"Number of non overlaps in users = {}\".format(counter))\n",
        "\n",
        "train_movies = list(train_filtered.movie_id.unique())\n",
        "test_movies = list(test_df.movie_id.unique())\n",
        "counter=0\n",
        "for movie in test_movies:\n",
        "    if movie not in train_movies:\n",
        "        counter =counter + 1\n",
        "\n",
        "print(\"Number movies in test that are not in train = {}\".format(counter))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Number of non overlaps in users = 0\n",
            "Number movies in test that are not in train = 0\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "twgUdRwG1eDD",
        "colab": {}
      },
      "source": [
        "pivot_train = train_filtered.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot_train.fillna(0, inplace = True)\n",
        "\n",
        "pivot_test = test_df.pivot_table(values = 'rating', index = 'movie_id', columns = 'user_id')\n",
        "pivot_test.fillna(0, inplace = True)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "ytJjs3pz1eDG",
        "outputId": "1c828244-158f-4289-b2d7-29a8dd26e196",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "pivot_train.shape, pivot_test.shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "((1290, 598), (1280, 596))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 81
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gKb15D9Z632C",
        "colab_type": "code",
        "outputId": "ea5336fc-3034-45ae-c089-97f3ee363b18",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 274
        }
      },
      "source": [
        "pivot_train.head()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>user_id</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>3</th>\n",
              "      <th>4</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>8</th>\n",
              "      <th>9</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>12</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>17</th>\n",
              "      <th>18</th>\n",
              "      <th>19</th>\n",
              "      <th>20</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>27</th>\n",
              "      <th>28</th>\n",
              "      <th>29</th>\n",
              "      <th>30</th>\n",
              "      <th>31</th>\n",
              "      <th>32</th>\n",
              "      <th>33</th>\n",
              "      <th>34</th>\n",
              "      <th>36</th>\n",
              "      <th>37</th>\n",
              "      <th>38</th>\n",
              "      <th>39</th>\n",
              "      <th>40</th>\n",
              "      <th>41</th>\n",
              "      <th>42</th>\n",
              "      <th>...</th>\n",
              "      <th>570</th>\n",
              "      <th>571</th>\n",
              "      <th>572</th>\n",
              "      <th>573</th>\n",
              "      <th>574</th>\n",
              "      <th>575</th>\n",
              "      <th>576</th>\n",
              "      <th>577</th>\n",
              "      <th>578</th>\n",
              "      <th>579</th>\n",
              "      <th>580</th>\n",
              "      <th>581</th>\n",
              "      <th>582</th>\n",
              "      <th>583</th>\n",
              "      <th>584</th>\n",
              "      <th>585</th>\n",
              "      <th>586</th>\n",
              "      <th>587</th>\n",
              "      <th>588</th>\n",
              "      <th>589</th>\n",
              "      <th>590</th>\n",
              "      <th>591</th>\n",
              "      <th>592</th>\n",
              "      <th>593</th>\n",
              "      <th>594</th>\n",
              "      <th>595</th>\n",
              "      <th>596</th>\n",
              "      <th>597</th>\n",
              "      <th>599</th>\n",
              "      <th>600</th>\n",
              "      <th>601</th>\n",
              "      <th>602</th>\n",
              "      <th>603</th>\n",
              "      <th>604</th>\n",
              "      <th>605</th>\n",
              "      <th>606</th>\n",
              "      <th>607</th>\n",
              "      <th>608</th>\n",
              "      <th>609</th>\n",
              "      <th>610</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie_id</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 598 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "user_id   1    2    3    4    5    6    7    ...  604  605  606  607  608  609  610\n",
              "movie_id                                     ...                                   \n",
              "1         3.0  0.0  0.0  0.0  2.0  0.0  0.0  ...  1.0  3.0  2.0  0.0  2.0  1.0  3.0\n",
              "2         0.0  0.0  0.0  0.0  0.0  4.0  0.0  ...  0.0  2.0  0.0  0.0  2.0  0.0  0.0\n",
              "3         0.0  0.0  0.0  0.0  0.0  1.0  0.0  ...  0.0  0.0  0.0  0.0  4.0  0.0  0.0\n",
              "5         0.0  0.0  0.0  0.0  0.0  2.0  0.0  ...  3.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "6         0.0  0.0  0.0  0.0  0.0  3.0  0.0  ...  1.0  0.0  0.0  0.0  0.0  0.0  3.0\n",
              "\n",
              "[5 rows x 598 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 82
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "4e88baf3-1333-4164-ad12-a0be3032dfcd",
        "id": "LRyIsGci1eDL",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 274
        }
      },
      "source": [
        "pivot_test.head(5)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>user_id</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>3</th>\n",
              "      <th>4</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>8</th>\n",
              "      <th>9</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>12</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>17</th>\n",
              "      <th>18</th>\n",
              "      <th>19</th>\n",
              "      <th>20</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>27</th>\n",
              "      <th>28</th>\n",
              "      <th>29</th>\n",
              "      <th>30</th>\n",
              "      <th>31</th>\n",
              "      <th>32</th>\n",
              "      <th>33</th>\n",
              "      <th>34</th>\n",
              "      <th>36</th>\n",
              "      <th>37</th>\n",
              "      <th>38</th>\n",
              "      <th>39</th>\n",
              "      <th>40</th>\n",
              "      <th>41</th>\n",
              "      <th>42</th>\n",
              "      <th>43</th>\n",
              "      <th>...</th>\n",
              "      <th>570</th>\n",
              "      <th>571</th>\n",
              "      <th>572</th>\n",
              "      <th>573</th>\n",
              "      <th>574</th>\n",
              "      <th>575</th>\n",
              "      <th>576</th>\n",
              "      <th>577</th>\n",
              "      <th>578</th>\n",
              "      <th>579</th>\n",
              "      <th>580</th>\n",
              "      <th>581</th>\n",
              "      <th>582</th>\n",
              "      <th>583</th>\n",
              "      <th>584</th>\n",
              "      <th>585</th>\n",
              "      <th>586</th>\n",
              "      <th>587</th>\n",
              "      <th>588</th>\n",
              "      <th>589</th>\n",
              "      <th>590</th>\n",
              "      <th>591</th>\n",
              "      <th>592</th>\n",
              "      <th>593</th>\n",
              "      <th>594</th>\n",
              "      <th>595</th>\n",
              "      <th>596</th>\n",
              "      <th>597</th>\n",
              "      <th>599</th>\n",
              "      <th>600</th>\n",
              "      <th>601</th>\n",
              "      <th>602</th>\n",
              "      <th>603</th>\n",
              "      <th>604</th>\n",
              "      <th>605</th>\n",
              "      <th>606</th>\n",
              "      <th>607</th>\n",
              "      <th>608</th>\n",
              "      <th>609</th>\n",
              "      <th>610</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie_id</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 596 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "user_id   1    2    3    4    5    6    7    ...  604  605  606  607  608  609  610\n",
              "movie_id                                     ...                                   \n",
              "1         0.0  0.0  0.0  0.0  0.0  0.0  3.0  ...  0.0  0.0  0.0  4.0  0.0  0.0  0.0\n",
              "2         0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  3.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "3         4.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "5         0.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "6         4.0  0.0  0.0  0.0  0.0  0.0  0.0  ...  0.0  0.0  0.0  0.0  0.0  0.0  0.0\n",
              "\n",
              "[5 rows x 596 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 83
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "278dfc75-5983-4dad-b651-0f87664a4410",
        "id": "iLzuSeQu1eDV",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "print(\"Train set contains {} ratings\".format(np.sum(np.sum(pivot_train>0))))\n",
        "print(\"Test set contains {} ratings\".format(np.sum(np.sum(pivot_test>0))))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Train set contains 54246 ratings\n",
            "Test set contains 13165 ratings\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "7fbb4757-2e8e-40f3-ecf1-e0858c94d0d7",
        "id": "eyvYWaez1eDj",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "#Checking if movies in the test set are included in the train set\n",
        "\n",
        "s_test = set(pivot_test.columns)\n",
        "s_train = set(pivot_train.columns)\n",
        "\n",
        "inter = s_test.issubset(s_train)\n",
        "inter, len(s_train), len(s_test)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(True, 598, 596)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 85
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "KcRuDj4a1eDo"
      },
      "source": [
        "### Training the CF algorithm on the train-pivot table, to test it later over the test pivot table:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "wH7FpYtY1eDp",
        "colab": {}
      },
      "source": [
        "from scipy import optimize\n",
        "\n",
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by 943 users\n",
        "\n",
        "Y = pivot_train.values\n",
        "\n",
        "#  R is a 1682x943 matrix, where R(i,j) = 1 if and only if user j gave a rating to movie i\n",
        "\n",
        "idx = np.where(pivot_train>0)\n",
        "\n",
        "R = np.zeros_like(Y)\n",
        "\n",
        "R[idx] = 1\n",
        "\n",
        "#  Useful Values\n",
        "num_movies, num_users = pivot_train.shape\n",
        "num_features = [1, 5,10]\n",
        "# Set Regularization\n",
        "\n",
        "lambda_ = [3,4,5]\n",
        "# Set options for scipy.optimize.minimize\n",
        "options = [{'maxiter': 80}, {'maxiter': 100},{'maxiter': 125}, {'maxiter': 150}]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "wvGMJYIE1eDz",
        "colab": {}
      },
      "source": [
        "def trainRecommender(Y, R, X, Theta, n_users, features, reg, option, verbose=0):\n",
        "    \n",
        "    Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "    res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                                   num_movies, features, reg),\n",
        "                            initial_parameters,\n",
        "                            method='TNC',\n",
        "                            jac=True,\n",
        "                            options=option)\n",
        "    theta = res.x\n",
        "\n",
        "    # Unfold the returned theta back into U and W\n",
        "    X = theta[:num_movies*features].reshape(num_movies, features)\n",
        "    Theta = theta[num_movies*features:].reshape(num_users, features)\n",
        "\n",
        "    if verbose:\n",
        "        print('Recommender system learning completed.')\n",
        "    \n",
        "    return (X, Theta, Ynorm, Ymean)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "af1f2cf8-cf78-42b0-ebba-e21cf6bb68e6",
        "id": "g3H7Za9q1eD3",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "#Lazy Grid Search - looping over all the options\n",
        "\n",
        "results = []\n",
        "rnd = 0\n",
        "\n",
        "for ftrs in num_features:\n",
        "    for regu in lambda_:\n",
        "        for option in options:\n",
        "            \n",
        "            #  X : (num_movies  x num_features) matrix of movie features >>>   X = (1682 X p)\n",
        "            #  Theta : (num_users  x num_features) matrix of user features >>> Theta = (943 X p)\n",
        "\n",
        "            # Set Initial Parameters (Theta, X)\n",
        "            X = np.random.randn(num_movies, ftrs)\n",
        "            Theta = np.random.randn(num_users, ftrs)\n",
        "\n",
        "            initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n",
        "            \n",
        "            X, Theta, Ynorm, Ymean = trainRecommender(Y, R, X, Theta, num_users, ftrs, regu, option)\n",
        "            \n",
        "            #Predictions:\n",
        "            p = np.dot(X, Theta.T)\n",
        "\n",
        "            #Adding back the mean of every movie, Ymean\n",
        "            predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "            train_predictions = pd.DataFrame(predictions)\n",
        "            train_predictions.columns = pivot_train.columns\n",
        "            \n",
        "            '''\n",
        "            The best way I've found to do this..\n",
        "            Looping over the test pivot and locating the corresponding cell in the train set,\n",
        "            by INDEX, where the test-pivot has a rating.\n",
        "            '''\n",
        "            true_val = []\n",
        "            validation_val = []\n",
        "                 \n",
        "            tmp = list(np.setdiff1d(pivot_test.index, train_predictions.index))\n",
        "            for i in pivot_test.index:\n",
        "                for j in pivot_test.columns:\n",
        "                    if (pivot_test.loc[i,j]!=0) and (i not in tmp):\n",
        "#                         print('i = {},j = {}'.format(i,j))\n",
        "                        validation_val.append(train_predictions.loc[i,j])\n",
        "                        true_val.append(pivot_test.loc[i,j])\n",
        "                        \n",
        "            true_val = np.array(true_val)\n",
        "            validation_val = np.array(validation_val)\n",
        "            RMSE = np.round(np.sqrt(np.square(true_val - validation_val).mean()),4)\n",
        "            MAE = np.round(np.abs(true_val - validation_val).mean(),4)\n",
        "            \n",
        "            print('RMSE: {}, MAE: {}'.format(RMSE, MAE))\n",
        "            print(\"number of features: {}, iter: {}, lambda: {}\".format(ftrs, option, regu))\n",
        "            \n",
        "            results.append([RMSE, MAE, ftrs, option, regu])\n",
        "            rnd+=1"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "RMSE: 1.0327, MAE: 0.8168\n",
            "number of features: 1, iter: {'maxiter': 80}, lambda: 3\n",
            "RMSE: 1.029, MAE: 0.8146\n",
            "number of features: 1, iter: {'maxiter': 100}, lambda: 3\n",
            "RMSE: 1.0324, MAE: 0.8158\n",
            "number of features: 1, iter: {'maxiter': 125}, lambda: 3\n",
            "RMSE: 1.0309, MAE: 0.8154\n",
            "number of features: 1, iter: {'maxiter': 150}, lambda: 3\n",
            "RMSE: 1.028, MAE: 0.813\n",
            "number of features: 1, iter: {'maxiter': 80}, lambda: 4\n",
            "RMSE: 1.0284, MAE: 0.8147\n",
            "number of features: 1, iter: {'maxiter': 100}, lambda: 4\n",
            "RMSE: 1.0251, MAE: 0.811\n",
            "number of features: 1, iter: {'maxiter': 125}, lambda: 4\n",
            "RMSE: 1.0299, MAE: 0.8155\n",
            "number of features: 1, iter: {'maxiter': 150}, lambda: 4\n",
            "RMSE: 1.0252, MAE: 0.8093\n",
            "number of features: 1, iter: {'maxiter': 80}, lambda: 5\n",
            "RMSE: 1.0237, MAE: 0.8063\n",
            "number of features: 1, iter: {'maxiter': 100}, lambda: 5\n",
            "RMSE: 1.0268, MAE: 0.8112\n",
            "number of features: 1, iter: {'maxiter': 125}, lambda: 5\n",
            "RMSE: 1.025, MAE: 0.8081\n",
            "number of features: 1, iter: {'maxiter': 150}, lambda: 5\n",
            "RMSE: 1.1004, MAE: 0.883\n",
            "number of features: 5, iter: {'maxiter': 80}, lambda: 3\n",
            "RMSE: 1.081, MAE: 0.8702\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 3\n",
            "RMSE: 1.0966, MAE: 0.8778\n",
            "number of features: 5, iter: {'maxiter': 125}, lambda: 3\n",
            "RMSE: 1.0986, MAE: 0.8865\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 3\n",
            "RMSE: 1.0648, MAE: 0.8521\n",
            "number of features: 5, iter: {'maxiter': 80}, lambda: 4\n",
            "RMSE: 1.074, MAE: 0.8588\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 4\n",
            "RMSE: 1.0753, MAE: 0.86\n",
            "number of features: 5, iter: {'maxiter': 125}, lambda: 4\n",
            "RMSE: 1.0698, MAE: 0.8557\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 4\n",
            "RMSE: 1.0453, MAE: 0.8324\n",
            "number of features: 5, iter: {'maxiter': 80}, lambda: 5\n",
            "RMSE: 1.0652, MAE: 0.8505\n",
            "number of features: 5, iter: {'maxiter': 100}, lambda: 5\n",
            "RMSE: 1.0618, MAE: 0.8479\n",
            "number of features: 5, iter: {'maxiter': 125}, lambda: 5\n",
            "RMSE: 1.0606, MAE: 0.8505\n",
            "number of features: 5, iter: {'maxiter': 150}, lambda: 5\n",
            "RMSE: 1.1319, MAE: 0.9082\n",
            "number of features: 10, iter: {'maxiter': 80}, lambda: 3\n",
            "RMSE: 1.1178, MAE: 0.8993\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 3\n",
            "RMSE: 1.151, MAE: 0.924\n",
            "number of features: 10, iter: {'maxiter': 125}, lambda: 3\n",
            "RMSE: 1.1333, MAE: 0.9093\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 3\n",
            "RMSE: 1.089, MAE: 0.8766\n",
            "number of features: 10, iter: {'maxiter': 80}, lambda: 4\n",
            "RMSE: 1.0907, MAE: 0.8756\n",
            "number of features: 10, iter: {'maxiter': 100}, lambda: 4\n",
            "RMSE: 1.1144, MAE: 0.8957\n",
            "number of features: 10, iter: {'maxiter': 125}, lambda: 4\n",
            "RMSE: 1.121, MAE: 0.8975\n",
            "number of features: 10, iter: {'maxiter': 150}, lambda: 4\n",
            "RMSE: 1.0809, MAE: 0.8675\n",
            "number of features: 10, iter: {'maxiter': 80}, lambda: 5\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "error",
          "ename": "KeyboardInterrupt",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-88-dda804f26dde>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     16\u001b[0m             \u001b[0minitial_parameters\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconcatenate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTheta\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mravel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m             \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTheta\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mYnorm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mYmean\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtrainRecommender\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mY\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mR\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mX\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mTheta\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnum_users\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mftrs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mregu\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moption\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     19\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     20\u001b[0m             \u001b[0;31m#Predictions:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m<ipython-input-87-b7d0f251d70e>\u001b[0m in \u001b[0;36mtrainRecommender\u001b[0;34m(Y, R, X, Theta, n_users, features, reg, option, verbose)\u001b[0m\n\u001b[1;32m      8\u001b[0m                             \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'TNC'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m                             \u001b[0mjac\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m                             options=option)\n\u001b[0m\u001b[1;32m     11\u001b[0m     \u001b[0mtheta\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mres\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     12\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/scipy/optimize/_minimize.py\u001b[0m in \u001b[0;36mminimize\u001b[0;34m(fun, x0, args, method, jac, hess, hessp, bounds, constraints, tol, callback, options)\u001b[0m\n\u001b[1;32m    601\u001b[0m     \u001b[0;32melif\u001b[0m \u001b[0mmeth\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'tnc'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    602\u001b[0m         return _minimize_tnc(fun, x0, args, jac, bounds, callback=callback,\n\u001b[0;32m--> 603\u001b[0;31m                              **options)\n\u001b[0m\u001b[1;32m    604\u001b[0m     \u001b[0;32melif\u001b[0m \u001b[0mmeth\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'cobyla'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    605\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0m_minimize_cobyla\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfun\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mconstraints\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0moptions\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/scipy/optimize/tnc.py\u001b[0m in \u001b[0;36m_minimize_tnc\u001b[0;34m(fun, x0, args, jac, bounds, eps, scale, offset, mesg_num, maxCGit, maxiter, eta, stepmx, accuracy, minfev, ftol, xtol, gtol, rescale, disp, callback, **unknown_options)\u001b[0m\n\u001b[1;32m    407\u001b[0m                                         \u001b[0moffset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmessages\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmaxCGit\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmaxfun\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    408\u001b[0m                                         \u001b[0meta\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstepmx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maccuracy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfmin\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mftol\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 409\u001b[0;31m                                         xtol, pgtol, rescale, callback)\n\u001b[0m\u001b[1;32m    410\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    411\u001b[0m     \u001b[0mfunv\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mjacv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfunc_and_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/scipy/optimize/tnc.py\u001b[0m in \u001b[0;36mfunc_and_grad\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m    369\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    370\u001b[0m         \u001b[0;32mdef\u001b[0m \u001b[0mfunc_and_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 371\u001b[0;31m             \u001b[0mf\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    372\u001b[0m             \u001b[0mg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mjac\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    373\u001b[0m             \u001b[0;32mreturn\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/scipy/optimize/optimize.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, x, *args)\u001b[0m\n\u001b[1;32m     62\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     63\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masarray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m         \u001b[0mfg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfun\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     65\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjac\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfg\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     66\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0mfg\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m<ipython-input-87-b7d0f251d70e>\u001b[0m in \u001b[0;36m<lambda>\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n\u001b[0;32m----> 6\u001b[0;31m                                                    num_movies, features, reg),\n\u001b[0m\u001b[1;32m      7\u001b[0m                             \u001b[0minitial_parameters\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m                             \u001b[0mmethod\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'TNC'\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;32m<ipython-input-69-caf823fc66d8>\u001b[0m in \u001b[0;36mcofiCostFunc\u001b[0;34m(params, Y, R, num_users, num_movies, num_features, lambda_)\u001b[0m\n\u001b[1;32m     81\u001b[0m     \u001b[0mZ2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmultiply\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mR\u001b[0m \u001b[0;34m,\u001b[0m \u001b[0mM\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m-\u001b[0m \u001b[0mY\u001b[0m \u001b[0;31m#(m * n)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     82\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 83\u001b[0;31m     \u001b[0mX_grad\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mZ2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mTheta\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mlambda_\u001b[0m\u001b[0;34m*\u001b[0m \u001b[0mX\u001b[0m  \u001b[0;31m# (m*n)dot(n*p)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     84\u001b[0m     \u001b[0mTheta_grad\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mZ2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mT\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mX\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mlambda_\u001b[0m\u001b[0;34m*\u001b[0m \u001b[0mTheta\u001b[0m \u001b[0;31m# (m*n)dot(m*p)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "htX-9xYcAz-8",
        "colab_type": "code",
        "outputId": "28c8adb7-1af6-4f12-9dae-a0e4956bd4b8",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 366
        }
      },
      "source": [
        "results = pd.DataFrame(results)\n",
        "results.columns = ['RMSE', 'MAE', 'NumOfFeatures', 'Iter', 'Lambda']\n",
        "\n",
        "print(\"Grid search results:\")\n",
        "results.sort_values(by='RMSE').head(10)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Grid search results:\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>RMSE</th>\n",
              "      <th>MAE</th>\n",
              "      <th>NumOfFeatures</th>\n",
              "      <th>Iter</th>\n",
              "      <th>Lambda</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>1.0943</td>\n",
              "      <td>0.8762</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 80}</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>1.0943</td>\n",
              "      <td>0.8755</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>4</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>1.0943</td>\n",
              "      <td>0.8755</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>4</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>1.0943</td>\n",
              "      <td>0.8755</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 125}</td>\n",
              "      <td>4</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>1.0944</td>\n",
              "      <td>0.8762</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 100}</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>11</th>\n",
              "      <td>1.0944</td>\n",
              "      <td>0.8762</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10</th>\n",
              "      <td>1.0944</td>\n",
              "      <td>0.8762</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 125}</td>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1.0947</td>\n",
              "      <td>0.8751</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 80}</td>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>1.0947</td>\n",
              "      <td>0.8751</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 150}</td>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1.0947</td>\n",
              "      <td>0.8751</td>\n",
              "      <td>1</td>\n",
              "      <td>{'maxiter': 125}</td>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "      RMSE     MAE  NumOfFeatures              Iter  Lambda\n",
              "8   1.0943  0.8762              1   {'maxiter': 80}       5\n",
              "7   1.0943  0.8755              1  {'maxiter': 150}       4\n",
              "5   1.0943  0.8755              1  {'maxiter': 100}       4\n",
              "6   1.0943  0.8755              1  {'maxiter': 125}       4\n",
              "9   1.0944  0.8762              1  {'maxiter': 100}       5\n",
              "11  1.0944  0.8762              1  {'maxiter': 150}       5\n",
              "10  1.0944  0.8762              1  {'maxiter': 125}       5\n",
              "0   1.0947  0.8751              1   {'maxiter': 80}       3\n",
              "3   1.0947  0.8751              1  {'maxiter': 150}       3\n",
              "2   1.0947  0.8751              1  {'maxiter': 125}       3"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 38
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "rWgIFAq_g326",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "#Best Params = \n",
        "# NumOfFeatures\t=1\n",
        "# Lambda = 3\n",
        "# Iter = 80"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WoOWizoNHuWC",
        "colab_type": "text"
      },
      "source": [
        "### Training the algorithm with the best parameters"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "8mbDG79rHzqY",
        "outputId": "ebb31d0a-29c6-4a81-8a0d-6b40c825f59d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 54
        }
      },
      "source": [
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by 943 users\n",
        "\n",
        "Y = pivot_train.values\n",
        "\n",
        "#  R is a 1682x943 matrix, where R(i,j) = 1 if and only if user j gave a rating to movie i\n",
        "\n",
        "idx = np.where(pivot_train>0)\n",
        "\n",
        "R = np.zeros_like(Y)\n",
        "\n",
        "R[idx] = 1\n",
        "\n",
        "#  Useful Values\n",
        "num_movies, num_users = pivot_train.shape\n",
        "\n",
        "ftrs = 1\n",
        "regu = 3\n",
        "option = {'maxiter': 80}\n",
        "\n",
        "\n",
        "X = np.random.randn(num_movies, ftrs)\n",
        "Theta = np.random.randn(num_users, ftrs)\n",
        "\n",
        "initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n",
        "\n",
        "X, Theta, Ynorm, Ymean = trainRecommender(Y, R, X, Theta, num_users, ftrs, regu, option)\n",
        "\n",
        "#Predictions:\n",
        "p = np.dot(X, Theta.T)\n",
        "\n",
        "#Adding back the mean of every movie, Ymean\n",
        "predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "train_predictions = pd.DataFrame(predictions)\n",
        "train_predictions.columns = pivot_train.columns\n",
        "\n",
        "'''\n",
        "The best way I've found to do this..\n",
        "Looping over the test pivot and locating the corresponding cell in the train set,\n",
        "by INDEX, where the test-pivot has a rating.\n",
        "'''\n",
        "true_val = []\n",
        "validation_val = []\n",
        "\n",
        "tmp = list(np.setdiff1d(pivot_test.index, train_predictions.index))\n",
        "for i in pivot_test.index:\n",
        "    for j in pivot_test.columns:\n",
        "        if (pivot_test.loc[i,j]!=0) and (i not in tmp):\n",
        "#                         print('i = {},j = {}'.format(i,j))\n",
        "            validation_val.append(train_predictions.loc[i,j])\n",
        "            true_val.append(pivot_test.loc[i,j])\n",
        "\n",
        "true_val = np.array(true_val)\n",
        "validation_val = np.array(validation_val)\n",
        "RMSE = np.round(np.sqrt(np.square(true_val - validation_val).mean()),4)\n",
        "MAE = np.round(np.abs(true_val - validation_val).mean(),4)\n",
        "\n",
        "print('RMSE: {}, MAE: {}'.format(RMSE, MAE))\n",
        "print(\"number of features: {}, iter: {}, lambda: {}\".format(ftrs, option, regu))\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "RMSE: 1.0949, MAE: 0.8753\n",
            "number of features: 1, iter: {'maxiter': 80}, lambda: 3\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "b61a11aa-6838-43ab-d304-d09a5667059c",
        "id": "mCSEw4t-IlhF",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "pd.DataFrame(zip(true_val ,validation_val), columns = ['true', 'predicted'])"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>true</th>\n",
              "      <th>predicted</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.157936</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>3.0</td>\n",
              "      <td>3.514359</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>5.0</td>\n",
              "      <td>4.241178</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.058355</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.516705</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.174579</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>3.0</td>\n",
              "      <td>2.646330</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>2.0</td>\n",
              "      <td>2.797049</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.417857</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.009414</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.945238</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>11</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.967919</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>12</th>\n",
              "      <td>3.0</td>\n",
              "      <td>3.225004</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>13</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.682277</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>14</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.112517</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>15</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.678821</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>16</th>\n",
              "      <td>2.0</td>\n",
              "      <td>2.382617</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>17</th>\n",
              "      <td>4.0</td>\n",
              "      <td>2.843421</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>18</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.309221</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>19</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.032180</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.880105</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>21</th>\n",
              "      <td>3.0</td>\n",
              "      <td>3.198601</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>22</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.862504</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>23</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.788184</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>24</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.224832</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>25</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.254802</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>26</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.462936</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>27</th>\n",
              "      <td>2.5</td>\n",
              "      <td>3.518984</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>28</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.678251</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>29</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.326711</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>...</th>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2981</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.622891</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2982</th>\n",
              "      <td>3.0</td>\n",
              "      <td>2.917101</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2983</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.200017</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2984</th>\n",
              "      <td>2.0</td>\n",
              "      <td>4.119418</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2985</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.607202</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2986</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.617563</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2987</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.799518</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2988</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.863936</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2989</th>\n",
              "      <td>4.0</td>\n",
              "      <td>4.009310</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2990</th>\n",
              "      <td>3.5</td>\n",
              "      <td>4.102727</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2991</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.828054</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2992</th>\n",
              "      <td>5.0</td>\n",
              "      <td>4.219848</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2993</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.645606</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2994</th>\n",
              "      <td>2.5</td>\n",
              "      <td>2.597073</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2995</th>\n",
              "      <td>5.0</td>\n",
              "      <td>4.480508</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2996</th>\n",
              "      <td>3.0</td>\n",
              "      <td>3.444753</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2997</th>\n",
              "      <td>4.5</td>\n",
              "      <td>4.743536</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2998</th>\n",
              "      <td>3.0</td>\n",
              "      <td>2.956980</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2999</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.646964</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3000</th>\n",
              "      <td>4.0</td>\n",
              "      <td>2.951670</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3001</th>\n",
              "      <td>4.0</td>\n",
              "      <td>2.992899</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3002</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.331984</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3003</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.652720</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3004</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.386676</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3005</th>\n",
              "      <td>4.0</td>\n",
              "      <td>3.312632</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3006</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.608592</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3007</th>\n",
              "      <td>5.0</td>\n",
              "      <td>3.319614</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3008</th>\n",
              "      <td>5.0</td>\n",
              "      <td>4.069434</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3009</th>\n",
              "      <td>3.5</td>\n",
              "      <td>3.655619</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3010</th>\n",
              "      <td>4.5</td>\n",
              "      <td>3.515880</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>3011 rows × 2 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "      true  predicted\n",
              "0      4.5   3.157936\n",
              "1      3.0   3.514359\n",
              "2      5.0   4.241178\n",
              "3      5.0   3.058355\n",
              "4      4.0   3.516705\n",
              "5      4.0   3.174579\n",
              "6      3.0   2.646330\n",
              "7      2.0   2.797049\n",
              "8      4.0   3.417857\n",
              "9      4.5   3.009414\n",
              "10     5.0   3.945238\n",
              "11     5.0   3.967919\n",
              "12     3.0   3.225004\n",
              "13     4.5   3.682277\n",
              "14     4.5   3.112517\n",
              "15     4.0   3.678821\n",
              "16     2.0   2.382617\n",
              "17     4.0   2.843421\n",
              "18     4.0   3.309221\n",
              "19     3.5   3.032180\n",
              "20     5.0   3.880105\n",
              "21     3.0   3.198601\n",
              "22     5.0   3.862504\n",
              "23     4.5   3.788184\n",
              "24     4.0   3.224832\n",
              "25     3.5   3.254802\n",
              "26     4.0   3.462936\n",
              "27     2.5   3.518984\n",
              "28     4.5   3.678251\n",
              "29     4.0   3.326711\n",
              "...    ...        ...\n",
              "2981   5.0   3.622891\n",
              "2982   3.0   2.917101\n",
              "2983   3.5   3.200017\n",
              "2984   2.0   4.119418\n",
              "2985   4.0   3.607202\n",
              "2986   3.5   3.617563\n",
              "2987   4.0   3.799518\n",
              "2988   4.0   3.863936\n",
              "2989   4.0   4.009310\n",
              "2990   3.5   4.102727\n",
              "2991   3.5   3.828054\n",
              "2992   5.0   4.219848\n",
              "2993   3.5   3.645606\n",
              "2994   2.5   2.597073\n",
              "2995   5.0   4.480508\n",
              "2996   3.0   3.444753\n",
              "2997   4.5   4.743536\n",
              "2998   3.0   2.956980\n",
              "2999   4.0   3.646964\n",
              "3000   4.0   2.951670\n",
              "3001   4.0   2.992899\n",
              "3002   4.5   3.331984\n",
              "3003   4.0   3.652720\n",
              "3004   4.0   3.386676\n",
              "3005   4.0   3.312632\n",
              "3006   5.0   3.608592\n",
              "3007   5.0   3.319614\n",
              "3008   5.0   4.069434\n",
              "3009   3.5   3.655619\n",
              "3010   4.5   3.515880\n",
              "\n",
              "[3011 rows x 2 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 77
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-vugThVZFQNm",
        "colab_type": "code",
        "outputId": "a5f96e2c-cc11-404d-d1ee-bee4d49135af",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 287
        }
      },
      "source": [
        "pd.DataFrame(zip(true_val ,validation_val), columns=['true_val', 'predicted']).plot()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<matplotlib.axes._subplots.AxesSubplot at 0x7f76118aad30>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 50
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "gta8xQuwg0_l"
      },
      "source": [
        "## Seeing your own recommendations!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "AEPlM87Wg0_p"
      },
      "source": [
        "Movie list:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GnFK9OTYkmQg",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "bestmovies = pd.DataFrame(index = movies.movie_id.index)\n",
        "bestmovies['number of ratings'] =  movielens.pivot_table(index = 'movie_id', values = 'rating', aggfunc='count')\n",
        "bestmovies['mean of rating'] = round(movielens.pivot_table(index = 'movie_id', values = 'rating', aggfunc='mean'),2)\n",
        "bestmovies['std of rating'] = round(movielens.pivot_table(index = 'movie_id', values = 'rating', aggfunc='std'), 2)\n",
        "# bestmovies['movie name'] = movies.loc[movies.movie_id == bestmovies.index]['title']\n",
        "\n",
        "bestmovies.sort_values(by = 'number of ratings',ascending=False)\n",
        "\n",
        "# bestmovies.corr()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "6b39fef5-949c-4ea3-a875-3116c7bbe596",
        "id": "2X4Ka0Aqg0_q",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 648
        }
      },
      "source": [
        "movieList = movies['title']\n",
        "movieList['movie_id'] = movies['movie_id']\n",
        "n_m = len(movieList)\n",
        "pd.DataFrame(movieList).head(20)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>Jumanji (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>Grumpier Old Men (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>Waiting to Exhale (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>Father of the Bride Part II (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>Heat (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>Sabrina (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>Tom and Huck (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>Sudden Death (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>10</th>\n",
              "      <td>GoldenEye (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>11</th>\n",
              "      <td>American President, The (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>12</th>\n",
              "      <td>Dracula: Dead and Loving It (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>13</th>\n",
              "      <td>Balto (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>14</th>\n",
              "      <td>Nixon (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>15</th>\n",
              "      <td>Cutthroat Island (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>16</th>\n",
              "      <td>Casino (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>17</th>\n",
              "      <td>Sense and Sensibility (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>18</th>\n",
              "      <td>Four Rooms (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>19</th>\n",
              "      <td>Ace Ventura: When Nature Calls (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>20</th>\n",
              "      <td>Money Train (1995)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                                    title\n",
              "1                        Toy Story (1995)\n",
              "2                          Jumanji (1995)\n",
              "3                 Grumpier Old Men (1995)\n",
              "4                Waiting to Exhale (1995)\n",
              "5      Father of the Bride Part II (1995)\n",
              "6                             Heat (1995)\n",
              "7                          Sabrina (1995)\n",
              "8                     Tom and Huck (1995)\n",
              "9                     Sudden Death (1995)\n",
              "10                       GoldenEye (1995)\n",
              "11         American President, The (1995)\n",
              "12     Dracula: Dead and Loving It (1995)\n",
              "13                           Balto (1995)\n",
              "14                           Nixon (1995)\n",
              "15                Cutthroat Island (1995)\n",
              "16                          Casino (1995)\n",
              "17           Sense and Sensibility (1995)\n",
              "18                      Four Rooms (1995)\n",
              "19  Ace Ventura: When Nature Calls (1995)\n",
              "20                     Money Train (1995)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 144
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "cd5dea4b-a5d6-4861-be03-0ff3eeafc1ba",
        "id": "j1JxdBY4g0_y",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 126
        }
      },
      "source": [
        "#Adding our own ratings\n",
        "\n",
        "n_m = pivot_train.values.shape[0]\n",
        "\n",
        "#  Initialize my ratings\n",
        "my_ratings = np.zeros(n_m)\n",
        "\n",
        "\n",
        "# my_ratings[4993] = 5\n",
        "my_ratings[1080] = 5\n",
        "my_ratings[260] = 5\n",
        "# my_ratings[4896] = 5\n",
        "my_ratings[1196] = 5\n",
        "my_ratings[1210] = 5\n",
        "# my_ratings[2628] = 5\n",
        "# my_ratings[5378] = 5\n",
        "\n",
        "\n",
        "\n",
        "\n",
        "print('User ratings:')\n",
        "print('-----------------')\n",
        "\n",
        "for i, val in enumerate(my_ratings):\n",
        "    if val > 0:\n",
        "        print('Rated %d stars: %s' % (val, movies.loc[movies.movie_id==str(i)].title.values))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "User ratings:\n",
            "-----------------\n",
            "Rated 5 stars: ['Star Wars: Episode IV - A New Hope (1977)']\n",
            "Rated 5 stars: [\"Monty Python's Life of Brian (1979)\"]\n",
            "Rated 5 stars: ['Star Wars: Episode V - The Empire Strikes Back (1980)']\n",
            "Rated 5 stars: ['Star Wars: Episode VI - Return of the Jedi (1983)']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "a6437fa5-0b04-430a-82c3-1a04072e548b",
        "id": "jONd-gaUg0_5",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "Y.shape, R.shape, X.shape, Theta.shape"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "((663, 327), (663, 327), (663, 5), (327, 5))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 196
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HSx-xbJKkXWJ",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "pivot_train"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "5w4-YVblOiBF",
        "colab_type": "code",
        "outputId": "78e95b92-05f2-4619-e288-05b2d7e1c4ca",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 90
        }
      },
      "source": [
        "#  Y is a 1682x943 matrix, containing ratings (1-5) of 1682 movies by 943 users\n",
        "\n",
        "Y = pivot_train.values\n",
        "\n",
        "R = Y > 0\n",
        "\n",
        "print(\"Adding your recommendations!\")\n",
        "Y = np.hstack([my_ratings[:, None], Y])\n",
        "R = np.hstack([(my_ratings > 0)[:, None], R])\n",
        "\n",
        "#  Normalize Ratings\n",
        "Ynorm, Ymean = normalizeRatings(Y, R)\n",
        "\n",
        "#  Useful Values\n",
        "num_movies, num_users = Y.shape\n",
        "\n",
        "num_features = 30\n",
        "\n",
        "# Set Initial Parameters (Theta, X)\n",
        "X = np.random.randn(num_movies, num_features)\n",
        "Theta = np.random.randn(num_users, num_features)\n",
        "\n",
        "initial_parameters = np.concatenate([X.ravel(), Theta.ravel()])\n",
        "\n",
        "# Set options for scipy.optimize.minimize\n",
        "options = {'maxiter': 50}\n",
        "\n",
        "# Set Regularization\n",
        "lambda_ = 20\n",
        "\n",
        "#Optimizing using Gradient Descent (in scipy)\n",
        "res = optimize.minimize(lambda x: cofiCostFunc(x, Ynorm, R, num_users,\n",
        "                                               num_movies, num_features, lambda_),\n",
        "                        initial_parameters,\n",
        "                        method='L-BFGS-B',\n",
        "                        jac=True,\n",
        "                        options=options)\n",
        "theta = res.x\n",
        "\n",
        "# Unfold the returned theta back into U and W\n",
        "X = theta[:num_movies*num_features].reshape(num_movies, num_features)\n",
        "Theta = theta[num_movies*num_features:].reshape(num_users, num_features)\n",
        "\n",
        "print('Recommender system learning completed.')\n",
        "\n",
        "\n",
        "#Predictions:\n",
        "p = np.dot(X, Theta.T)\n",
        "\n",
        "#Adding back the mean of every movie, Ymean\n",
        "predictions = p +  Ymean[:,np.newaxis]  #<< broadcasting, adding the Ymean vector to each column of p\n",
        "\n",
        "train_predictions = pd.DataFrame(predictions)\n",
        "columns = list(pivot_train.columns)\n",
        "columns = [0] + columns\n",
        "\n",
        "train_predictions.columns = columns\n",
        "\n",
        "print(predictions.shape)\n",
        "\n",
        "\n",
        "\n",
        "true_val = []\n",
        "validation_val = []\n",
        "\n",
        "tmp = list(np.setdiff1d(pivot_test.index, train_predictions.index))\n",
        "for i in pivot_test.index:\n",
        "    for j in pivot_test.columns:\n",
        "        if (pivot_test.loc[i,j]!=0) and (i not in tmp):\n",
        "#             print('i = {},j = {}'.format(i,j))\n",
        "            validation_val.append(train_predictions.loc[i,j])\n",
        "            true_val.append(pivot_test.loc[i,j])\n",
        "\n",
        "true_val = np.array(true_val)\n",
        "validation_val = np.array(validation_val)\n",
        "RMSE = np.round(np.sqrt(np.square(true_val - validation_val).mean()),4)\n",
        "MAE = np.round(np.abs(true_val - validation_val).mean(),4)\n",
        "\n",
        "print('RMSE: {}, MAE: {}'.format(RMSE, MAE))\n",
        "my_predictions = predictions[:,0]\n"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Adding your recommendations!\n",
            "Recommender system learning completed.\n",
            "(1605, 775)\n",
            "RMSE: 1.1473, MAE: 0.9199\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "u6pAw7e0s4AA",
        "colab_type": "code",
        "outputId": "663c4333-7e9f-4056-b810-8a970ba2ae54",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 35
        }
      },
      "source": [
        "Y[:,0][np.where(Y[:,0]>0)]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array([5., 5., 5., 5., 5., 5., 5., 5.])"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 262
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "c0d58da2-a989-4b53-a292-3b1dd2de0081",
        "id": "h1t3Hjdgg1AF",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "ix = np.argsort(my_predictions)[::-1]\n",
        "\n",
        "print('Top recommendations for you:')\n",
        "print('----------------------------')\n",
        "for i in range(50):\n",
        "    j = ix[i]\n",
        "    print('Predicting rating %.3f - %s' % (my_predictions[j], movieList[j]))\n",
        "\n",
        "print('User ratings:')\n",
        "print('-----------------')\n",
        "\n",
        "for i, val in enumerate(my_ratings):\n",
        "    if val > 0:\n",
        "        print('Rated %d stars: %s' % (val, movies.loc[movies.movie_id==str(i)].title.values))"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Top recommendations for you:\n",
            "----------------------------\n",
            "Predicting rating 4.483 - Meet Me in St. Louis (1944)\n",
            "Predicting rating 4.462 - Congo (1995)\n",
            "Predicting rating 4.461 - Emma (1996)\n",
            "Predicting rating 4.452 - Clear and Present Danger (1994)\n",
            "Predicting rating 4.439 - What's Eating Gilbert Grape (1993)\n",
            "Predicting rating 4.414 - Thousand Acres, A (1997)\n",
            "Predicting rating 4.383 - House of the Spirits, The (1993)\n",
            "Predicting rating 4.376 - Hard Target (1993)\n",
            "Predicting rating 4.371 - Perfect World, A (1993)\n",
            "Predicting rating 4.364 - Firm, The (1993)\n",
            "Predicting rating 4.355 - Scout, The (1994)\n",
            "Predicting rating 4.351 - Kansas City (1996)\n",
            "Predicting rating 4.340 - In the Name of the Father (1993)\n",
            "Predicting rating 4.336 - Shining, The (1980)\n",
            "Predicting rating 4.327 - Dangerous Minds (1995)\n",
            "Predicting rating 4.322 - Cheech and Chong's Up in Smoke (1978)\n",
            "Predicting rating 4.318 - Naked (1993)\n",
            "Predicting rating 4.317 - Swing Kids (1993)\n",
            "Predicting rating 4.316 - Star Trek: Generations (1994)\n",
            "Predicting rating 4.314 - Roommates (1995)\n",
            "Predicting rating 4.303 - Somebody to Love (1994)\n",
            "Predicting rating 4.296 - Malice (1993)\n",
            "Predicting rating 4.291 - Four Weddings and a Funeral (1994)\n",
            "Predicting rating 4.290 - Picture Bride (Bijo photo) (1994)\n",
            "Predicting rating 4.270 - Rudy (1993)\n",
            "Predicting rating 4.266 - Muppet Treasure Island (1996)\n",
            "Predicting rating 4.264 - Dirty Dancing (1987)\n",
            "Predicting rating 4.263 - Killing Zoe (1994)\n",
            "Predicting rating 4.251 - Cobb (1994)\n",
            "Predicting rating 4.237 - Entertaining Angels: The Dorothy Day Story (1996)\n",
            "Predicting rating 4.236 - Big Lebowski, The (1998)\n",
            "Predicting rating 4.235 - Muriel's Wedding (1994)\n",
            "Predicting rating 4.234 - Something Wicked This Way Comes (1983)\n",
            "Predicting rating 4.231 - Radioland Murders (1994)\n",
            "Predicting rating 4.225 - I'll Do Anything (1994)\n",
            "Predicting rating 4.225 - Farinelli: il castrato (1994)\n",
            "Predicting rating 4.224 - Lassie (1994)\n",
            "Predicting rating 4.220 - Village of the Damned (1995)\n",
            "Predicting rating 4.219 - With Honors (1994)\n",
            "Predicting rating 4.217 - Baby-Sitters Club, The (1995)\n",
            "Predicting rating 4.217 - Amateur (1994)\n",
            "Predicting rating 4.212 - Client, The (1994)\n",
            "Predicting rating 4.212 - Tommy Boy (1995)\n",
            "Predicting rating 4.211 - My Favorite Year (1982)\n",
            "Predicting rating 4.207 - Jackie Brown (1997)\n",
            "Predicting rating 4.203 - Jaws (1975)\n",
            "Predicting rating 4.202 - Bound (1996)\n",
            "Predicting rating 4.201 - Deep Impact (1998)\n",
            "Predicting rating 4.200 - Backbeat (1993)\n",
            "Predicting rating 4.197 - Single Girl, A (Fille seule, La) (1995)\n",
            "User ratings:\n",
            "-----------------\n",
            "Rated 5 stars: ['Star Wars: Episode IV - A New Hope (1977)']\n",
            "Rated 5 stars: [\"Monty Python's Life of Brian (1979)\"]\n",
            "Rated 5 stars: ['Star Wars: Episode V - The Empire Strikes Back (1980)']\n",
            "Rated 5 stars: ['Star Wars: Episode VI - Return of the Jedi (1983)']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "Ker3eGlLg1AT",
        "colab": {}
      },
      "source": [
        "#Test Predictions\n",
        "\n",
        "N_min = min num of ratings per user\n",
        "M_min = min number of ratings per movie\n",
        "\n",
        "create new matrix based on N_min and M_min\n",
        "\n",
        "TrainSet = for each instance reduce %of|constant from sample (e.g. leave out 5 randim ratings to test predictions)\n",
        "TestSet = predictions left out\n",
        "\n",
        "make prediction on TrainSet\n",
        "calculate RMSE for each user\n",
        "total score = mean of RMSE ?\n",
        "\n",
        "which movies got the lowest RMSE?\n",
        "check number of ratings per movie * RMSE\n",
        "\n",
        "create the UltimateList - 10-15 movie list that can be splited ot Train-Test and will preform "
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "outputId": "c379d73a-de67-4806-c743-07e87849b9fb",
        "id": "iVyPm2lPg1AV",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 402
        }
      },
      "source": [
        "ratings.iloc[:,:3]"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user_id</th>\n",
              "      <th>movie_id</th>\n",
              "      <th>rating</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>195</td>\n",
              "      <td>241</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>185</td>\n",
              "      <td>301</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>21</td>\n",
              "      <td>376</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>243</td>\n",
              "      <td>50</td>\n",
              "      <td>2.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>165</td>\n",
              "      <td>345</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>...</th>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99995</th>\n",
              "      <td>879</td>\n",
              "      <td>475</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99996</th>\n",
              "      <td>715</td>\n",
              "      <td>203</td>\n",
              "      <td>5.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99997</th>\n",
              "      <td>275</td>\n",
              "      <td>1089</td>\n",
              "      <td>1.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99998</th>\n",
              "      <td>12</td>\n",
              "      <td>224</td>\n",
              "      <td>2.000</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>99999</th>\n",
              "      <td>11</td>\n",
              "      <td>202</td>\n",
              "      <td>3.000</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>100000 rows × 3 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "      user_id movie_id  rating\n",
              "0         195      241   3.000\n",
              "1         185      301   3.000\n",
              "2          21      376   1.000\n",
              "3         243       50   2.000\n",
              "4         165      345   1.000\n",
              "...       ...      ...     ...\n",
              "99995     879      475   3.000\n",
              "99996     715      203   5.000\n",
              "99997     275     1089   1.000\n",
              "99998      12      224   2.000\n",
              "99999      11      202   3.000\n",
              "\n",
              "[100000 rows x 3 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 15
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "colab_type": "code",
        "id": "xzC86Q_Lg1Aj",
        "colab": {}
      },
      "source": [
        "from scipy.sparse import csr_matrix\n",
        "\n",
        "# pivot ratings into movie features\n",
        "df_movie_features = ratings.iloc[:,:3].pivot(\n",
        "    index='movie_id',\n",
        "    columns='user_id',\n",
        "    values='rating'\n",
        ").fillna(0)\n",
        "# convert dataframe of movie features to scipy sparse matrix\n",
        "mat_movie_features = csr_matrix(df_movie_features.values)"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}
